Skip to content

Commit c0ad186

Browse files
authored
Merge pull request #2 from arkpar/arkpar/trie
2 parents 15f1b2b + 43b9d3c commit c0ad186

File tree

2 files changed

+242
-0
lines changed

2 files changed

+242
-0
lines changed

trie/merkle.py

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
#!/usr/bin/env python3
2+
3+
import hashlib
4+
import json
5+
import sys
6+
7+
## Graypaper conforming implementation of the binary tree used for the state merklization (Appendix D)
8+
## Based on GP 0.2.2
9+
10+
# Blake2b-256
11+
def hash(data):
12+
return hashlib.blake2b(data, digest_size=32).digest()
13+
14+
# GP (286)
15+
def branch(l, r):
16+
assert len(l) == 32
17+
assert len(r) == 32
18+
head = l[0] & 0xfe
19+
return bytes([head]) + l[1:] + r
20+
21+
# GP (287)
22+
def leaf(k, v):
23+
if len(v) <= 32:
24+
head = 0b01 | (len(v) << 2)
25+
return bytes([head]) + k[:-1] + v + ((32 - len(v)) * b'\0')
26+
head = 0b11
27+
return bytes([head]) + k[:-1] + hash(v)
28+
29+
def bit(k, i):
30+
return (k[i >> 3] & (1 << (i & 7))) != 0
31+
32+
# GP (289)
33+
def merkle(kvs, i=0):
34+
if not kvs:
35+
return 32 * b'\0'
36+
if len(kvs) == 1:
37+
encoded = leaf(*kvs[0])
38+
else:
39+
l = []
40+
r = []
41+
for k, v in kvs:
42+
if bit(k, i):
43+
r.append((k, v))
44+
else:
45+
l.append((k, v))
46+
encoded = branch(merkle(l, i + 1), merkle(r, i + 1))
47+
assert len(encoded) == 64
48+
return hash(encoded)
49+
50+
## Random number generation
51+
52+
def wrap_64(x):
53+
return x & ((1 << 64) - 1)
54+
55+
def rol_64(x, y):
56+
return wrap_64(x << y) | (x >> (64 - y))
57+
58+
class Rng:
59+
'''Xoshiro256** RNG.
60+
61+
Matches Xoshiro256StarStar in crates.io's rand_xoshiro 0.6.0 with rand 0.8.5.'''
62+
63+
def __init__(self, seed):
64+
def split_mix_64():
65+
nonlocal seed
66+
seed = wrap_64(seed + 0x9e3779b97f4a7c15)
67+
res = wrap_64((seed ^ (seed >> 30)) * 0xbf58476d1ce4e5b9)
68+
res = wrap_64((res ^ (res >> 27)) * 0x94d049bb133111eb)
69+
return res ^ (res >> 31)
70+
71+
self.__s = [split_mix_64() for i in range(4)]
72+
73+
def next_64(self):
74+
res = wrap_64(rol_64(wrap_64(self.__s[1] * 5), 7) * 9)
75+
76+
t = wrap_64(self.__s[1] << 17)
77+
78+
self.__s[2] ^= self.__s[0]
79+
self.__s[3] ^= self.__s[1]
80+
self.__s[1] ^= self.__s[2]
81+
self.__s[0] ^= self.__s[3]
82+
83+
self.__s[2] ^= t
84+
85+
self.__s[3] = rol_64(self.__s[3], 45)
86+
87+
return res
88+
89+
def next_32(self):
90+
return self.next_64() >> 32
91+
92+
def bytes(self, num):
93+
data = bytearray()
94+
while len(data) < num:
95+
if (num - len(data)) > 4:
96+
data.extend(self.next_64().to_bytes(8, byteorder='little'))
97+
else:
98+
data.extend(self.next_32().to_bytes(4, byteorder='little'))
99+
return bytes(data[:num])
100+
101+
def range_64(self, low, high):
102+
assert 0 <= low <= high < (1 << 64)
103+
104+
r = high - low + 1
105+
if r == (1 << 64):
106+
assert low == 0
107+
return self.next_64()
108+
109+
zone = r << (64 - r.bit_length())
110+
while True:
111+
x = self.next_64() * r
112+
if wrap_64(x) < zone:
113+
return low + (x >> 64)
114+
115+
## Test vector generation
116+
117+
def random_key(rng):
118+
return rng.bytes(32)
119+
120+
def random_value(rng, size=None):
121+
if size is None:
122+
size = rng.range_64(0, 64)
123+
return rng.bytes(size)
124+
125+
def inputs():
126+
rng = Rng(42)
127+
128+
yield []
129+
yield [(random_key(rng), b'')]
130+
yield [(random_key(rng), random_value(rng, 1))]
131+
yield [(random_key(rng), random_value(rng, 32))]
132+
yield [(random_key(rng), random_value(rng, 33))]
133+
yield [(random_key(rng), random_value(rng, 60))]
134+
135+
k1 = random_key(rng)
136+
k2 = bytes([k1[0] ^ 1]) + k1[1:]
137+
yield [(k1, random_value(rng)), (k2, random_value(rng))]
138+
139+
k1 = random_key(rng)
140+
k2 = k1[:1] + bytes([k1[1] ^ 1]) + k1[2:]
141+
yield [(k1, random_value(rng)), (k2, random_value(rng))]
142+
143+
yield [(random_key(rng), random_value(rng)) for i in range(2)]
144+
yield [(random_key(rng), random_value(rng)) for i in range(5)]
145+
yield [(random_key(rng), random_value(rng)) for i in range(10)]
146+
147+
def hex(data):
148+
return ''.join(f'{x:02x}' for x in data)
149+
150+
def test_vectors():
151+
for kvs in inputs():
152+
yield {
153+
'input': {hex(k): hex(v) for k, v in kvs},
154+
'output': hex(merkle(kvs)),
155+
}
156+
157+
def main():
158+
json.dump(list(test_vectors()), sys.stdout, indent=' ')
159+
160+
main()

trie/trie.json

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
[
2+
{
3+
"input": {},
4+
"output": "0000000000000000000000000000000000000000000000000000000000000000"
5+
},
6+
{
7+
"input": {
8+
"16c72e0c2e0b78157e3a116d86d90461a199e439325317aea160b30347adb8ec": ""
9+
},
10+
"output": "17d7a1c738dfa055bc810110004585ca79be323586764e14179ee20e54376592"
11+
},
12+
{
13+
"input": {
14+
"645eece27fdce6fd3852790131a50dc5b2dd655a855421b88700e6eb43279ad9": "72"
15+
},
16+
"output": "75978696ab7bd70492c2abbecf26fd03eb2c41e0d83daf968f45c20f566b9a9b"
17+
},
18+
{
19+
"input": {
20+
"3dbc5f775f6156957139100c343bb5ae6589af7398db694ab6c60630a9ed0fcd": "4227b4a465084852cd87d8f23bec0db6fa7766b9685ab5e095ef9cda9e15e49d"
21+
},
22+
"output": "9ea1799e255f9b5edb960cf6640aa42ec2fac24a199be8155853ddcce9b896c4"
23+
},
24+
{
25+
"input": {
26+
"d44438ec54b3f4d9771a43ed435f21b53a4f1f42be4c34b5d998bb9d53adc517": "2bdea5ab5a70d42dbd29c5944a90aa6f1774815854a21d9af07a9ca98d936150c0"
27+
},
28+
"output": "de6ffcbc0c3c6e3e5b6ef8f7ba875b77707f502228db0b6b9173b3f659b8edb6"
29+
},
30+
{
31+
"input": {
32+
"d484d55a6f532466b844c01500e503cafad33b4f4f1493a2da0b3b1377bd383b": "fd3b2d4981a80d6a3a2b500dd3516b9f6891b0a2b93af8dc1285af7c3ebbdbf18a8d2615c5a26fd00c46d64112603bbfb765cfa460c1dac87de5790b"
33+
},
34+
"output": "720f6a3acf7c3de97febd9508c7a9e4d0a12fb65283588f596aeb4e2423d3bda"
35+
},
36+
{
37+
"input": {
38+
"f2a9fcaf8ae0ff770b0908ebdee1daf8457c0ef5e1106c89ad364236333c5fb3": "22c62f84ee5775d1e75ba6519f6dfae571eb1888768f2a203281579656b6a29097f7c7e2cf44e38da9a541d9b4c773db8b71e1d3",
39+
"f3a9fcaf8ae0ff770b0908ebdee1daf8457c0ef5e1106c89ad364236333c5fb3": "44d0b26211d9d4a44e375207"
40+
},
41+
"output": "b9c99f66e5784879a178795b63ae178f8a49ee113652a122cd4b3b2a321418c1"
42+
},
43+
{
44+
"input": {
45+
"27a30d678b05b75bd7c5ce723d7dbe919c9ee57d03f687c6097228ae37d7db81": "ec568a22939875f3aba1c9d5751a8bf1114716dc12ca18389e30cca648d490c9f23817bb54135c12",
46+
"27a20d678b05b75bd7c5ce723d7dbe919c9ee57d03f687c6097228ae37d7db81": "e8a9e5097a500730bc63cb"
47+
},
48+
"output": "846fd6a4c1913db012ee6bf3184b85db4b9d9c3f429305c9c60ae610f6bd2d0b"
49+
},
50+
{
51+
"input": {
52+
"8e758c6d2b87bd72bb121e82801a212717d730343ed555bd8757f3f976eb5476": "74e30dd46bb8dcae80e82f7585a5d652e00cbf1b43a8873f6977b7891cbca312aaac17b7c6ab",
53+
"80542dacde2838f3383f47eca425ca657d4bb7814368be746cf57ea6df2f7da1": "384905461e004f92366ceb267347688aa01e9f8cd362"
54+
},
55+
"output": "e79ee404bb7caf984f99f7a5d997200a306b0302fa08262b380662562d693313"
56+
},
57+
{
58+
"input": {
59+
"d7f99b746f23411983df92806725af8e5cb66eba9f200737accae4a1ab7f47b9": "24232437f5b3f2380ba9089bdbc45efaffbe386602cb1ecc2c17f1d0",
60+
"59ee947b94bcc05634d95efb474742f6cd6531766e44670ec987270a6b5a4211": "72fdb0c99cf47feb85b2dad01ee163139ee6d34a8d893029a200aff76f4be5930b9000a1bbb2dc2b6c79f8f3c19906c94a3472349817af21181c3eef6b",
61+
"a3dc3bed1b0727caf428961bed11c9998ae2476d8a97fad203171b628363d9a2": "8a0dafa9d6ae6177",
62+
"15207c233b055f921701fc62b41a440d01dfa488016a97cc653a84afb5f94fd5": "157b6c821169dacabcf26690df",
63+
"b05ff8a05bb23c0d7b177d47ce466ee58fd55c6a0351a3040cf3cbf5225aab19": "6a208734106f38b73880684b"
64+
},
65+
"output": "55634c70b9dca56f2f40b343f750a5c9744798370cbf3f669e29ebe0b8d64ceb"
66+
},
67+
{
68+
"input": {
69+
"5dffe0e2c9f089d30e50b04ee562445cf2c0e7e7d677580ef0ccf2c6fa3522dd": "bb11c256876fe10442213dd78714793394d2016134c28a64eb27376ddc147fc6044df72bdea44d9ec66a3ea1e6d523f7de71db1d05a980e001e9fa",
70+
"df08871e8a54fde4834d83851469e635713615ab1037128df138a6cd223f1242": "b8bded4e1c",
71+
"7723a8383e43a1713eb920bae44880b2ae9225ea2d38c031cf3b22434b4507e7": "e46ddd41a5960807d528f5d9282568e622a023b94b72cb63f0353baff189257d",
72+
"3e7d409b9037b1fd870120de92ebb7285219ce4526c54701b888c5a13995f73c": "9bc5d0",
73+
"c2d3bda8f77cc483d2f4368cf998203097230fd353d2223e5a333eb58f76a429": "9ae1dc59670bd3ef6fb51cbbbc05f1d2635fd548cb31f72500000a",
74+
"6bf8460545baf5b0af874ebbbd56ae09ee73cd24926b4549238b797b447e050a": "0964801caa928bc8c1869d60dbf1d8233233e0261baf725f2631d2b27574efc0316ce3067b4fccfa607274",
75+
"832c15668a451578b4c69974085280b4bac5b01e220398f06e06a1d0aff2859a": "4881dd3238fd6c8af1090d455e7b449a",
76+
"c7a04effd2c0cede0279747f58bd210d0cc9d65c2eba265c6b4dfbc058a7047b": "d1fddfd63fd00cd6749a441b6ceaea1f250982a3a6b6d38f1b40cae00972cce3f9f4eaf7f9d7bc3070bd1e8d088500b10ca72e5ed5956f62",
77+
"9e78a15cc0b45c83c83218efadd234cbac22dbffb24a76e2eb5f6a81d32df616": "e8256c6b5a9623cf2b293090f78f8fbceea6fc3991ac5f872400608f14d2a8b3d494fcda1c51d93b9904e3242cdeaa4b227c68cea89cca05ab6b5296edf105",
78+
"03345958f90731bce89d07c2722dc693425a541b5230f99a6867882993576a23": "cd759a8d88edb46dda489a45ba6e48a42ce7efd36f1ca31d3bdfa40d2091f27740c5ec5de746d90d9841b986f575d545d0fb642398914eaab5"
79+
},
80+
"output": "0120dd8239fdc65ef0485215493b6de1b4b31b96d9bae99617afb6178e4d43e3"
81+
}
82+
]

0 commit comments

Comments
 (0)