Skip to content

Commit c241b8c

Browse files
committed
Added trie test vectors
1 parent bb69ad0 commit c241b8c

File tree

2 files changed

+237
-0
lines changed

2 files changed

+237
-0
lines changed

trie/merkle.py

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
#!/usr/bin/env python3
2+
3+
import hashlib
4+
import json
5+
import sys
6+
7+
## Reference implementation
8+
9+
def hash(data):
10+
return hashlib.blake2b(data, digest_size=32).digest()
11+
12+
def fork(l, r):
13+
assert len(l) == 32
14+
assert len(r) == 32
15+
head = l[0] & 0x7f
16+
return bytes([head]) + l[1:] + r
17+
18+
def leaf(k, v):
19+
if 0 <= len(v) <= 32:
20+
head = (0b10 << 6) | len(v)
21+
return bytes([head]) + k[:-1] + v + ((32 - len(v)) * b'\0')
22+
head = (0b11 << 6)
23+
return bytes([head]) + k[:-1] + hash(v)
24+
25+
def bit(k, i):
26+
return (k[i >> 3] & (1 << (i & 7))) != 0
27+
28+
def merkle(kvs, i=0):
29+
if not kvs:
30+
return 32 * b'\0'
31+
if len(kvs) == 1:
32+
encoded = leaf(*kvs[0])
33+
else:
34+
l = []
35+
r = []
36+
for k, v in kvs:
37+
if bit(k, i):
38+
r.append((k, v))
39+
else:
40+
l.append((k, v))
41+
encoded = fork(merkle(l, i + 1), merkle(r, i + 1))
42+
assert len(encoded) == 64
43+
return hash(encoded)
44+
45+
## Random number generation
46+
47+
def wrap_64(x):
48+
return x & ((1 << 64) - 1)
49+
50+
def rol_64(x, y):
51+
return wrap_64(x << y) | (x >> (64 - y))
52+
53+
class Rng:
54+
'''Xoshiro256** RNG.
55+
56+
Matches Xoshiro256StarStar in crates.io's rand_xoshiro 0.6.0 with rand 0.8.5.'''
57+
58+
def __init__(self, seed):
59+
def split_mix_64():
60+
nonlocal seed
61+
seed = wrap_64(seed + 0x9e3779b97f4a7c15)
62+
res = wrap_64((seed ^ (seed >> 30)) * 0xbf58476d1ce4e5b9)
63+
res = wrap_64((res ^ (res >> 27)) * 0x94d049bb133111eb)
64+
return res ^ (res >> 31)
65+
66+
self.__s = [split_mix_64() for i in range(4)]
67+
68+
def next_64(self):
69+
res = wrap_64(rol_64(wrap_64(self.__s[1] * 5), 7) * 9)
70+
71+
t = wrap_64(self.__s[1] << 17)
72+
73+
self.__s[2] ^= self.__s[0]
74+
self.__s[3] ^= self.__s[1]
75+
self.__s[1] ^= self.__s[2]
76+
self.__s[0] ^= self.__s[3]
77+
78+
self.__s[2] ^= t
79+
80+
self.__s[3] = rol_64(self.__s[3], 45)
81+
82+
return res
83+
84+
def next_32(self):
85+
return self.next_64() >> 32
86+
87+
def bytes(self, num):
88+
data = bytearray()
89+
while len(data) < num:
90+
if (num - len(data)) > 4:
91+
data.extend(self.next_64().to_bytes(8, byteorder='little'))
92+
else:
93+
data.extend(self.next_32().to_bytes(4, byteorder='little'))
94+
return bytes(data[:num])
95+
96+
def range_64(self, low, high):
97+
assert 0 <= low <= high < (1 << 64)
98+
99+
r = high - low + 1
100+
if r == (1 << 64):
101+
assert low == 0
102+
return self.next_64()
103+
104+
zone = r << (64 - r.bit_length())
105+
while True:
106+
x = self.next_64() * r
107+
if wrap_64(x) < zone:
108+
return low + (x >> 64)
109+
110+
## Test vector generation
111+
112+
def random_key(rng):
113+
return rng.bytes(32)
114+
115+
def random_value(rng, size=None):
116+
if size is None:
117+
size = rng.range_64(0, 64)
118+
return rng.bytes(size)
119+
120+
def inputs():
121+
rng = Rng(42)
122+
123+
yield []
124+
yield [(random_key(rng), b'')]
125+
yield [(random_key(rng), random_value(rng, 1))]
126+
yield [(random_key(rng), random_value(rng, 32))]
127+
yield [(random_key(rng), random_value(rng, 33))]
128+
yield [(random_key(rng), random_value(rng, 60))]
129+
130+
k1 = random_key(rng)
131+
k2 = bytes([k1[0] ^ 1]) + k1[1:]
132+
yield [(k1, random_value(rng)), (k2, random_value(rng))]
133+
134+
k1 = random_key(rng)
135+
k2 = k1[:1] + bytes([k1[1] ^ 1]) + k1[2:]
136+
yield [(k1, random_value(rng)), (k2, random_value(rng))]
137+
138+
yield [(random_key(rng), random_value(rng)) for i in range(2)]
139+
yield [(random_key(rng), random_value(rng)) for i in range(5)]
140+
yield [(random_key(rng), random_value(rng)) for i in range(10)]
141+
142+
def hex(data):
143+
return ''.join(f'{x:02x}' for x in data)
144+
145+
def test_vectors():
146+
for kvs in inputs():
147+
yield {
148+
'input': {hex(k): hex(v) for k, v in kvs},
149+
'output': hex(merkle(kvs)),
150+
}
151+
152+
def main():
153+
json.dump(list(test_vectors()), sys.stdout, indent=' ')
154+
155+
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": "99ecb1509d2cbc16bab389714e5933932977e742472fcd9277d67f45699e076a"
11+
},
12+
{
13+
"input": {
14+
"645eece27fdce6fd3852790131a50dc5b2dd655a855421b88700e6eb43279ad9": "72"
15+
},
16+
"output": "e9a89ab2f10d45a46d47127110e8353d6443b635b08e989a743c27bb82740d7d"
17+
},
18+
{
19+
"input": {
20+
"3dbc5f775f6156957139100c343bb5ae6589af7398db694ab6c60630a9ed0fcd": "4227b4a465084852cd87d8f23bec0db6fa7766b9685ab5e095ef9cda9e15e49d"
21+
},
22+
"output": "5fd68f074c914741601931d64c6c772c18ab8a4cd0cd3a4fff0611a5d97ecc94"
23+
},
24+
{
25+
"input": {
26+
"d44438ec54b3f4d9771a43ed435f21b53a4f1f42be4c34b5d998bb9d53adc517": "2bdea5ab5a70d42dbd29c5944a90aa6f1774815854a21d9af07a9ca98d936150c0"
27+
},
28+
"output": "fb982161f7deefc8b66af5814a01396fba3cb78b6c826feedef9433fdd234666"
29+
},
30+
{
31+
"input": {
32+
"d484d55a6f532466b844c01500e503cafad33b4f4f1493a2da0b3b1377bd383b": "fd3b2d4981a80d6a3a2b500dd3516b9f6891b0a2b93af8dc1285af7c3ebbdbf18a8d2615c5a26fd00c46d64112603bbfb765cfa460c1dac87de5790b"
33+
},
34+
"output": "ef11722d05e21b20e7a37e355c685df020a4dcf22fb888f10b0138c7cd162461"
35+
},
36+
{
37+
"input": {
38+
"f2a9fcaf8ae0ff770b0908ebdee1daf8457c0ef5e1106c89ad364236333c5fb3": "22c62f84ee5775d1e75ba6519f6dfae571eb1888768f2a203281579656b6a29097f7c7e2cf44e38da9a541d9b4c773db8b71e1d3",
39+
"f3a9fcaf8ae0ff770b0908ebdee1daf8457c0ef5e1106c89ad364236333c5fb3": "44d0b26211d9d4a44e375207"
40+
},
41+
"output": "04f61a9c37615db4e1975b165084675383c82b321f3b011d533f3b6305b6c26c"
42+
},
43+
{
44+
"input": {
45+
"27a30d678b05b75bd7c5ce723d7dbe919c9ee57d03f687c6097228ae37d7db81": "ec568a22939875f3aba1c9d5751a8bf1114716dc12ca18389e30cca648d490c9f23817bb54135c12",
46+
"27a20d678b05b75bd7c5ce723d7dbe919c9ee57d03f687c6097228ae37d7db81": "e8a9e5097a500730bc63cb"
47+
},
48+
"output": "119c4fea2d58f783af0b247c8c63ddbdd7b408e69b15bca3e65ba169badd9763"
49+
},
50+
{
51+
"input": {
52+
"8e758c6d2b87bd72bb121e82801a212717d730343ed555bd8757f3f976eb5476": "74e30dd46bb8dcae80e82f7585a5d652e00cbf1b43a8873f6977b7891cbca312aaac17b7c6ab",
53+
"80542dacde2838f3383f47eca425ca657d4bb7814368be746cf57ea6df2f7da1": "384905461e004f92366ceb267347688aa01e9f8cd362"
54+
},
55+
"output": "79e8437049d4d249fbf175dcfdabd7ba1b169944cbbb6c7945e45e870e7510de"
56+
},
57+
{
58+
"input": {
59+
"d7f99b746f23411983df92806725af8e5cb66eba9f200737accae4a1ab7f47b9": "24232437f5b3f2380ba9089bdbc45efaffbe386602cb1ecc2c17f1d0",
60+
"59ee947b94bcc05634d95efb474742f6cd6531766e44670ec987270a6b5a4211": "72fdb0c99cf47feb85b2dad01ee163139ee6d34a8d893029a200aff76f4be5930b9000a1bbb2dc2b6c79f8f3c19906c94a3472349817af21181c3eef6b",
61+
"a3dc3bed1b0727caf428961bed11c9998ae2476d8a97fad203171b628363d9a2": "8a0dafa9d6ae6177",
62+
"15207c233b055f921701fc62b41a440d01dfa488016a97cc653a84afb5f94fd5": "157b6c821169dacabcf26690df",
63+
"b05ff8a05bb23c0d7b177d47ce466ee58fd55c6a0351a3040cf3cbf5225aab19": "6a208734106f38b73880684b"
64+
},
65+
"output": "1832e431ca23799dd91b136e7c3c3044f2ba55223afe9c46536ff1c1e44576d4"
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": "970e47a883f9ccd382def0da19d15b728c83c7307f8e2d83d3dcb3ca7ea6fa93"
81+
}
82+
]

0 commit comments

Comments
 (0)