From 87e0a6b57c9f152d5469f9074be516e9dd11bf9e Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Mon, 30 Aug 2021 19:14:55 +0100 Subject: [PATCH 01/12] zc_utils: Add support for parsing a compactSize. Signed-off-by: Daira Hopwood --- zc_utils.py | 57 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/zc_utils.py b/zc_utils.py index 06809ac..b9ff34d 100644 --- a/zc_utils.py +++ b/zc_utils.py @@ -10,18 +10,45 @@ def write_compact_size(n): else: return struct.pack('B', 255) + struct.pack('= 1 + b = rest[0] + if b < 253: + return (b, 1) + elif b == 253: + assert len(rest) >= 3 + return (struct.unpack('= 5 + return (struct.unpack('= 9 + return (struct.unpack(' Date: Mon, 30 Aug 2021 19:16:27 +0100 Subject: [PATCH 02/12] f4jumble: updates for large UAs/UVKs. Signed-off-by: Daira Hopwood --- f4jumble.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/f4jumble.py b/f4jumble.py index 613d328..8cf3983 100644 --- a/f4jumble.py +++ b/f4jumble.py @@ -8,17 +8,22 @@ from pyblake2 import blake2b from tv_output import render_args, render_tv from tv_rand import Rand +from utils import i2leosp # Maximum output length of BLAKE2b l_H = 64 assert 8*l_H == 512 +MIN_l_M = 48 +MAX_l_M = 4194368 +assert MAX_l_M == 65537*l_H + def instantiate(l_L, l_R): def H(i, u): digest = blake2b( digest_size=l_L, - person=b'UA_F4Jumble_H_' + bytes([i, 0]), + person=b'UA_F4Jumble_H' + bytes([i, 0, 0]), ) digest.update(u) return digest.digest() @@ -27,11 +32,11 @@ def instantiate(l_L, l_R): def inner(j): digest = blake2b( digest_size=l_H, - person=b'UA_F4Jumble_G_' + bytes([i, j]), + person=b'UA_F4Jumble_G' + bytes([i]) + i2leosp(16, j), ) digest.update(u) return digest.digest() - + return b''.join([inner(j) for j in range(0, math.ceil(l_R/l_H))])[:l_R] return (H, G) @@ -41,7 +46,7 @@ def xor(x, y): def f4jumble(M): l_M = len(M) - assert 48 <= l_M and l_M <= 16448 + assert MIN_l_M <= l_M and l_M <= MAX_l_M l_L = min([l_H, l_M//2]) l_R = l_M - l_L @@ -58,7 +63,7 @@ def f4jumble(M): def f4jumble_inv(M): l_M = len(M) - assert 48 <= l_M and l_M <= 16448 + assert MIN_l_M <= l_M and l_M <= MAX_l_M l_L = min([l_H, l_M//2]) l_R = l_M - l_L @@ -89,14 +94,16 @@ def main(): test_vectors = [] # Generate test vectors with various lengths: for l_M in [ - 48, + MIN_l_M, l_H, 2*l_H, 2*l_H + 1, 3*l_H, 3*l_H + 1, - (rand.u32() % 16400) + 48, - 16448, + 257*l_H, + 257*l_H + 1, + (rand.u32() % (MAX_l_M - MIN_l_M)) + MIN_l_M, + MAX_l_M, ]: M = rand.b(l_M) jumbled = f4jumble(M) From 29cae03b12e3afa9f8e29047b31fb2a19ca754f0 Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Mon, 30 Aug 2021 19:25:20 +0100 Subject: [PATCH 03/12] unified_address: updates for large UAs/UVKs. Signed-off-by: Daira Hopwood --- unified_address.py | 65 +++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/unified_address.py b/unified_address.py index c03041d..81165fd 100644 --- a/unified_address.py +++ b/unified_address.py @@ -4,17 +4,18 @@ import sys; assert sys.version_info[0] >= 3, "Python 3 required." import math import struct -from pyblake2 import blake2b from bech32m import bech32_encode, bech32_decode, convertbits, Encoding from tv_output import render_args, render_tv, Some from tv_rand import Rand +from zc_utils import write_compact_size, parse_compact_size from f4jumble import f4jumble, f4jumble_inv import sapling_key_components import orchard_key_components + def tlv(typecode, value): - return b"".join([bytes([typecode, len(value)]), value]) + return b"".join([write_compact_size(typecode), write_compact_size(len(value)), value]) def padding(hrp): assert(len(hrp) <= 16) @@ -51,46 +52,46 @@ def decode_unified(addr_str): suffix = decoded[-16:] # check trailing padding bytes assert suffix == padding(hrp) - decoded = decoded[:-16] + rest = decoded[:-16] s = 0 - acc = [] result = {} - for b in decoded: + while len(rest) > 0: if s == 0: - receiver_type = b + (receiver_type, receiver_type_len) = parse_compact_size(rest) + rest = rest[receiver_type_len:] + s = 1 elif s == 1: - receiver_len = b + (receiver_len, receiver_len_len) = parse_compact_size(rest) + rest = rest[receiver_len_len:] + expected_len = {0: 20, 1: 20, 2: 43, 3: 43}.get(receiver_type) if expected_len is not None: assert receiver_len == expected_len, "incorrect receiver length" s = 2 elif s == 2: - if len(acc) < receiver_len: - acc.append(b) - - if len(acc) == receiver_len: - if receiver_type == 0 or receiver_type == 1: - assert not ('transparent' in result), "duplicate transparent receiver detected" - assert len(acc) == 20 - result['transparent'] = bytes(acc) - acc = [] - s = 0 + assert len(rest) >= receiver_len + (receiver, rest) = (rest[:receiver_len], rest[receiver_len:]) - elif receiver_type == 2: - assert not ('sapling' in result), "duplicate sapling receiver detected" - assert len(acc) == 43 - result['sapling'] = bytes(acc) - acc = [] - s = 0 + if receiver_type == 0 or receiver_type == 1: + assert not ('transparent' in result), "duplicate transparent receiver detected" + assert len(receiver) == 20 + result['transparent'] = receiver + s = 0 + + elif receiver_type == 2: + assert not ('sapling' in result), "duplicate sapling receiver detected" + assert len(receiver) == 43 + result['sapling'] = receiver + s = 0 + + elif receiver_type == 3: + assert not ('orchard' in result), "duplicate orchard receiver detected" + assert len(receiver) == 43 + result['orchard'] = receiver + s = 0 - elif receiver_type == 3: - assert not ('orchard' in result), "duplicate orchard receiver detected" - assert len(acc) == 43 - result['orchard'] = bytes(acc) - acc = [] - s = 0 return result @@ -130,13 +131,13 @@ def main(): orchard_default_d = orchard_fvk.default_d() orchard_default_pk_d = orchard_fvk.default_pkd() orchard_raw_addr = b"".join([orchard_default_d[:11], bytes(orchard_default_pk_d)[:32]]) - else: + else: orchard_raw_addr = None is_p2pkh = rand.bool() receivers = [ - orchard_raw_addr, - sapling_raw_addr, + orchard_raw_addr, + sapling_raw_addr, (is_p2pkh, t_addr) ] ua = encode_unified(receivers) From 810c8bf275069cbb21d8d3acbe2355a7c95815c9 Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Mon, 30 Aug 2021 19:42:51 +0100 Subject: [PATCH 04/12] Simplify parse_compact_size usage. Signed-off-by: Daira Hopwood --- unified_address.py | 8 ++------ zc_utils.py | 12 ++++++------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/unified_address.py b/unified_address.py index 81165fd..a1dec6a 100644 --- a/unified_address.py +++ b/unified_address.py @@ -58,14 +58,10 @@ def decode_unified(addr_str): result = {} while len(rest) > 0: if s == 0: - (receiver_type, receiver_type_len) = parse_compact_size(rest) - rest = rest[receiver_type_len:] - + (receiver_type, rest) = parse_compact_size(rest) s = 1 elif s == 1: - (receiver_len, receiver_len_len) = parse_compact_size(rest) - rest = rest[receiver_len_len:] - + (receiver_len, rest) = parse_compact_size(rest) expected_len = {0: 20, 1: 20, 2: 43, 3: 43}.get(receiver_type) if expected_len is not None: assert receiver_len == expected_len, "incorrect receiver length" diff --git a/zc_utils.py b/zc_utils.py index b9ff34d..fcd1ca5 100644 --- a/zc_utils.py +++ b/zc_utils.py @@ -14,22 +14,22 @@ def parse_compact_size(rest): assert len(rest) >= 1 b = rest[0] if b < 253: - return (b, 1) + return (b, rest[1:]) elif b == 253: assert len(rest) >= 3 - return (struct.unpack('= 5 - return (struct.unpack('= 9 - return (struct.unpack(' Date: Mon, 30 Aug 2021 19:49:45 +0100 Subject: [PATCH 05/12] Further simplify parsing. This also ensures that the encoding ends with a receiver value, not a type or length. Signed-off-by: Daira Hopwood --- unified_address.py | 49 ++++++++++++++++++++-------------------------- 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/unified_address.py b/unified_address.py index a1dec6a..f1cfcf4 100644 --- a/unified_address.py +++ b/unified_address.py @@ -54,39 +54,32 @@ def decode_unified(addr_str): assert suffix == padding(hrp) rest = decoded[:-16] - s = 0 result = {} while len(rest) > 0: - if s == 0: - (receiver_type, rest) = parse_compact_size(rest) - s = 1 - elif s == 1: - (receiver_len, rest) = parse_compact_size(rest) - expected_len = {0: 20, 1: 20, 2: 43, 3: 43}.get(receiver_type) - if expected_len is not None: - assert receiver_len == expected_len, "incorrect receiver length" - s = 2 - elif s == 2: - assert len(rest) >= receiver_len - (receiver, rest) = (rest[:receiver_len], rest[receiver_len:]) + (receiver_type, rest) = parse_compact_size(rest) + (receiver_len, rest) = parse_compact_size(rest) - if receiver_type == 0 or receiver_type == 1: - assert not ('transparent' in result), "duplicate transparent receiver detected" - assert len(receiver) == 20 - result['transparent'] = receiver - s = 0 + expected_len = {0: 20, 1: 20, 2: 43, 3: 43}.get(receiver_type) + if expected_len is not None: + assert receiver_len == expected_len, "incorrect receiver length" - elif receiver_type == 2: - assert not ('sapling' in result), "duplicate sapling receiver detected" - assert len(receiver) == 43 - result['sapling'] = receiver - s = 0 + assert len(rest) >= receiver_len + (receiver, rest) = (rest[:receiver_len], rest[receiver_len:]) - elif receiver_type == 3: - assert not ('orchard' in result), "duplicate orchard receiver detected" - assert len(receiver) == 43 - result['orchard'] = receiver - s = 0 + if receiver_type == 0 or receiver_type == 1: + assert not ('transparent' in result), "duplicate transparent receiver detected" + assert len(receiver) == 20 + result['transparent'] = receiver + + elif receiver_type == 2: + assert not ('sapling' in result), "duplicate sapling receiver detected" + assert len(receiver) == 43 + result['sapling'] = receiver + + elif receiver_type == 3: + assert not ('orchard' in result), "duplicate orchard receiver detected" + assert len(receiver) == 43 + result['orchard'] = receiver return result From fa1bd3773ace1c57813d3a5fcfe971e98ddd2a21 Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Mon, 30 Aug 2021 23:50:53 +0100 Subject: [PATCH 06/12] zc_utils: Enforce canonicity in parse_compact_size. (It's not strictly needed for generating test vectors, but just in case this code gets reused.) Signed-off-by: Daira Hopwood --- zc_utils.py | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/zc_utils.py b/zc_utils.py index fcd1ca5..2ba5781 100644 --- a/zc_utils.py +++ b/zc_utils.py @@ -17,25 +17,34 @@ def parse_compact_size(rest): return (b, rest[1:]) elif b == 253: assert len(rest) >= 3 - return (struct.unpack('= 253 + return (n, rest[3:]) elif b == 254: assert len(rest) >= 5 - return (struct.unpack('= 0x10000 + return (n, rest[5:]) else: assert len(rest) >= 9 - return (struct.unpack('= 0x100000000 + return (n, rest[9:]) +def assert_parse_fails(encoding): + try: + parse_compact_size(encoding) + except AssertionError: + pass + else: + raise AssertionError("parse_compact_size(%r) failed to raise AssertionError" % (encoding,)) + def test_round_trip(n, encoding): assert write_compact_size(n) == encoding assert parse_compact_size(encoding) == (n, b'') assert parse_compact_size(encoding + b'*') == (n, b'*') - try: - parse_compact_size(encoding[:-1]) - except AssertionError: - pass - else: - raise AssertionError("parse_compact_size(%r) failed to raise AssertionError" % (encoding,)) + assert_parse_fails(encoding[:-1]) test_round_trip(0, b'\x00') test_round_trip(1, b'\x01') @@ -51,4 +60,7 @@ test_round_trip(0x010001, b'\xFE\x01\x00\x01\x00') test_round_trip(0xFFFFFFFE, b'\xFE\xFE\xFF\xFF\xFF') test_round_trip(0xFFFFFFFF, b'\xFE\xFF\xFF\xFF\xFF') test_round_trip(0x0100000000, b'\xFF\x00\x00\x00\x00\x01\x00\x00\x00') -test_round_trip(0xFFFFFFFFFFFFFFFF, b'\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF') + +assert_parse_fails(b'\xFD\xFC\x00') +assert_parse_fails(b'\xFE\xFF\xFF\x00\x00') +assert_parse_fails(b'\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00') From bdf4c9ff9b4ed298bc8fa91b6e0998898d5f1ef8 Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Tue, 31 Aug 2021 20:59:19 +0100 Subject: [PATCH 07/12] f4jumble: Use BLAKE2b hashes for the long test vectors. Signed-off-by: Daira Hopwood --- f4jumble.py | 41 ++++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/f4jumble.py b/f4jumble.py index 8cf3983..342cabd 100644 --- a/f4jumble.py +++ b/f4jumble.py @@ -91,7 +91,9 @@ def main(): return bytes(ret) rand = Rand(randbytes) - test_vectors = [] + plain_test_vectors = [] + hashed_test_vectors = [] + # Generate test vectors with various lengths: for l_M in [ MIN_l_M, @@ -102,19 +104,30 @@ def main(): 3*l_H + 1, 257*l_H, 257*l_H + 1, - (rand.u32() % (MAX_l_M - MIN_l_M)) + MIN_l_M, - MAX_l_M, ]: M = rand.b(l_M) jumbled = f4jumble(M) assert len(jumbled) == len(M) assert f4jumble_inv(jumbled) == M - test_vectors.append(M) - test_vectors = [{ - 'normal': M, - 'jumbled': f4jumble(M), - } for M in test_vectors] + plain_test_vectors.append({ + 'normal': M, + 'jumbled': jumbled, + }) + + for l_M in [ + (rand.u32() % (MAX_l_M - MIN_l_M)) + MIN_l_M, + MAX_l_M, + ]: + M = bytes([i & 0xFF for i in range(l_M)]) + jumbled = f4jumble(M) + assert len(jumbled) == len(M) + assert f4jumble_inv(jumbled) == M + + hashed_test_vectors.append({ + 'length': l_M, + 'jumbled_hash': blake2b(jumbled).digest() + }) render_tv( args, @@ -123,7 +136,17 @@ def main(): ('normal', 'Vec'), ('jumbled', 'Vec'), ), - test_vectors, + plain_test_vectors, + ) + print() + render_tv( + args, + 'f4jumble', + ( + ('length', 'usize'), + ('jumbled_hash', 'Vec'), + ), + hashed_test_vectors, ) From cbaca139a74c24a9dbc4c516e4f47583cb8372fa Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Wed, 15 Sep 2021 17:33:41 +0100 Subject: [PATCH 08/12] Split F4Jumble hashed test vectors into another file (`f4jumble_long.py`). Signed-off-by: Daira Hopwood --- f4jumble.py | 25 ------------------------- f4jumble_long.py | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 25 deletions(-) create mode 100755 f4jumble_long.py diff --git a/f4jumble.py b/f4jumble.py index 342cabd..f6f0e44 100644 --- a/f4jumble.py +++ b/f4jumble.py @@ -92,7 +92,6 @@ def main(): rand = Rand(randbytes) plain_test_vectors = [] - hashed_test_vectors = [] # Generate test vectors with various lengths: for l_M in [ @@ -115,20 +114,6 @@ def main(): 'jumbled': jumbled, }) - for l_M in [ - (rand.u32() % (MAX_l_M - MIN_l_M)) + MIN_l_M, - MAX_l_M, - ]: - M = bytes([i & 0xFF for i in range(l_M)]) - jumbled = f4jumble(M) - assert len(jumbled) == len(M) - assert f4jumble_inv(jumbled) == M - - hashed_test_vectors.append({ - 'length': l_M, - 'jumbled_hash': blake2b(jumbled).digest() - }) - render_tv( args, 'f4jumble', @@ -138,16 +123,6 @@ def main(): ), plain_test_vectors, ) - print() - render_tv( - args, - 'f4jumble', - ( - ('length', 'usize'), - ('jumbled_hash', 'Vec'), - ), - hashed_test_vectors, - ) if __name__ == "__main__": diff --git a/f4jumble_long.py b/f4jumble_long.py new file mode 100755 index 0000000..2b1553c --- /dev/null +++ b/f4jumble_long.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +import sys; assert sys.version_info[0] >= 3, "Python 3 required." + +from pyblake2 import blake2b + +from tv_output import render_args, render_tv +from f4jumble import f4jumble, f4jumble_inv, MAX_l_M + + +def main(): + args = render_args() + + hashed_test_vectors = [] + + for l_M in [ + 3246395, + MAX_l_M, + ]: + M = bytes([i & 0xFF for i in range(l_M)]) + jumbled = f4jumble(M) + assert len(jumbled) == len(M) + assert f4jumble_inv(jumbled) == M + + hashed_test_vectors.append({ + 'length': l_M, + 'jumbled_hash': blake2b(jumbled).digest() + }) + + render_tv( + args, + 'f4jumble_long', + ( + ('length', 'usize'), + ('jumbled_hash', 'Vec'), + ), + hashed_test_vectors, + ) + + +if __name__ == "__main__": + main() From f15c51c6801345b7de31d8ffd216104b6f49f2c5 Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Wed, 15 Sep 2021 17:45:10 +0100 Subject: [PATCH 09/12] zc_utils.py: restore 2^64 - 1 test vector. Signed-off-by: Daira Hopwood --- zc_utils.py | 2 ++ 1 file changed, 2 insertions(+) mode change 100644 => 100755 zc_utils.py diff --git a/zc_utils.py b/zc_utils.py old mode 100644 new mode 100755 index 2ba5781..e730ba5 --- a/zc_utils.py +++ b/zc_utils.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python3 import struct def write_compact_size(n): @@ -60,6 +61,7 @@ test_round_trip(0x010001, b'\xFE\x01\x00\x01\x00') test_round_trip(0xFFFFFFFE, b'\xFE\xFE\xFF\xFF\xFF') test_round_trip(0xFFFFFFFF, b'\xFE\xFF\xFF\xFF\xFF') test_round_trip(0x0100000000, b'\xFF\x00\x00\x00\x00\x01\x00\x00\x00') +test_round_trip(0xFFFFFFFFFFFFFFFF, b'\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF') assert_parse_fails(b'\xFD\xFC\x00') assert_parse_fails(b'\xFE\xFF\xFF\x00\x00') From efee9dcb039708620fef5a4b09ee09008ab83ff6 Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Wed, 15 Sep 2021 17:32:09 +0100 Subject: [PATCH 10/12] chmod +x for scripts and make the shebang/preamble consistent. Signed-off-by: Daira Hopwood --- f4jumble.py | 0 ff1.py | 0 orchard_commitments.py | 0 orchard_empty_roots.py | 3 +++ orchard_generators.py | 0 orchard_group_hash.py | 0 orchard_key_components.py | 0 orchard_map_to_curve.py | 1 + orchard_merkle_tree.py | 0 orchard_note_encryption.py | 1 + orchard_poseidon.py | 3 +++ orchard_poseidon_hash.py | 3 +++ sapling_generators.py | 0 sapling_key_components.py | 0 sapling_merkle_tree.py | 0 sapling_note_encryption.py | 0 sapling_signatures.py | 0 sapling_zip32.py | 0 transaction.py | 1 - unified_address.py | 0 zc_utils.py | 2 ++ zip_0143.py | 2 ++ zip_0243.py | 2 ++ zip_0244.py | 2 ++ 24 files changed, 19 insertions(+), 1 deletion(-) mode change 100644 => 100755 f4jumble.py mode change 100644 => 100755 ff1.py mode change 100644 => 100755 orchard_commitments.py mode change 100644 => 100755 orchard_empty_roots.py mode change 100644 => 100755 orchard_generators.py mode change 100644 => 100755 orchard_group_hash.py mode change 100644 => 100755 orchard_key_components.py mode change 100644 => 100755 orchard_merkle_tree.py mode change 100644 => 100755 orchard_note_encryption.py mode change 100644 => 100755 orchard_poseidon.py mode change 100644 => 100755 orchard_poseidon_hash.py mode change 100644 => 100755 sapling_generators.py mode change 100644 => 100755 sapling_key_components.py mode change 100644 => 100755 sapling_merkle_tree.py mode change 100644 => 100755 sapling_note_encryption.py mode change 100644 => 100755 sapling_signatures.py mode change 100644 => 100755 sapling_zip32.py mode change 100644 => 100755 unified_address.py mode change 100644 => 100755 zip_0143.py mode change 100644 => 100755 zip_0243.py mode change 100644 => 100755 zip_0244.py diff --git a/f4jumble.py b/f4jumble.py old mode 100644 new mode 100755 diff --git a/ff1.py b/ff1.py old mode 100644 new mode 100755 diff --git a/orchard_commitments.py b/orchard_commitments.py old mode 100644 new mode 100755 diff --git a/orchard_empty_roots.py b/orchard_empty_roots.py old mode 100644 new mode 100755 index 9358036..fb52896 --- a/orchard_empty_roots.py +++ b/orchard_empty_roots.py @@ -1,3 +1,6 @@ +#!/usr/bin/env python3 +import sys; assert sys.version_info[0] >= 3, "Python 3 required." + from orchard_merkle_tree import empty_roots from orchard_pallas import Fp from tv_output import render_args, render_tv diff --git a/orchard_generators.py b/orchard_generators.py old mode 100644 new mode 100755 diff --git a/orchard_group_hash.py b/orchard_group_hash.py old mode 100644 new mode 100755 diff --git a/orchard_key_components.py b/orchard_key_components.py old mode 100644 new mode 100755 diff --git a/orchard_map_to_curve.py b/orchard_map_to_curve.py index 840ed9f..d38140d 100755 --- a/orchard_map_to_curve.py +++ b/orchard_map_to_curve.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +import sys; assert sys.version_info[0] >= 3, "Python 3 required." from orchard_group_hash import map_to_curve_simple_swu from orchard_iso_pallas import Point as IsoPoint diff --git a/orchard_merkle_tree.py b/orchard_merkle_tree.py old mode 100644 new mode 100755 diff --git a/orchard_note_encryption.py b/orchard_note_encryption.py old mode 100644 new mode 100755 index fb09b36..ce09c95 --- a/orchard_note_encryption.py +++ b/orchard_note_encryption.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 import sys; assert sys.version_info[0] >= 3, "Python 3 required." + import struct from chacha20poly1305 import ChaCha20Poly1305 diff --git a/orchard_poseidon.py b/orchard_poseidon.py old mode 100644 new mode 100755 index 86b5087..4b1e591 --- a/orchard_poseidon.py +++ b/orchard_poseidon.py @@ -1,3 +1,6 @@ +#!/usr/bin/env python3 +import sys; assert sys.version_info[0] >= 3, "Python 3 required." + from orchard_pallas import Fp import numpy as np from itertools import chain diff --git a/orchard_poseidon_hash.py b/orchard_poseidon_hash.py old mode 100644 new mode 100755 index fc238d1..9d6dc68 --- a/orchard_poseidon_hash.py +++ b/orchard_poseidon_hash.py @@ -1,3 +1,6 @@ +#!/usr/bin/env python3 +import sys; assert sys.version_info[0] >= 3, "Python 3 required." + from orchard_pallas import Fp from orchard_poseidon import perm from utils import leos2ip diff --git a/sapling_generators.py b/sapling_generators.py old mode 100644 new mode 100755 diff --git a/sapling_key_components.py b/sapling_key_components.py old mode 100644 new mode 100755 diff --git a/sapling_merkle_tree.py b/sapling_merkle_tree.py old mode 100644 new mode 100755 diff --git a/sapling_note_encryption.py b/sapling_note_encryption.py old mode 100644 new mode 100755 diff --git a/sapling_signatures.py b/sapling_signatures.py old mode 100644 new mode 100755 diff --git a/sapling_zip32.py b/sapling_zip32.py old mode 100644 new mode 100755 diff --git a/transaction.py b/transaction.py index ac5f803..0ca65d1 100644 --- a/transaction.py +++ b/transaction.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import struct from orchard_pallas import ( diff --git a/unified_address.py b/unified_address.py old mode 100644 new mode 100755 diff --git a/zc_utils.py b/zc_utils.py index e730ba5..13e9fa9 100755 --- a/zc_utils.py +++ b/zc_utils.py @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +import sys; assert sys.version_info[0] >= 3, "Python 3 required." + import struct def write_compact_size(n): diff --git a/zip_0143.py b/zip_0143.py old mode 100644 new mode 100755 index 9859371..5b3cd09 --- a/zip_0143.py +++ b/zip_0143.py @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +import sys; assert sys.version_info[0] >= 3, "Python 3 required." + from pyblake2 import blake2b import struct diff --git a/zip_0243.py b/zip_0243.py old mode 100644 new mode 100755 index 03dd681..7118c94 --- a/zip_0243.py +++ b/zip_0243.py @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +import sys; assert sys.version_info[0] >= 3, "Python 3 required." + from pyblake2 import blake2b import struct diff --git a/zip_0244.py b/zip_0244.py old mode 100644 new mode 100755 index c07f6ed..c886d62 --- a/zip_0244.py +++ b/zip_0244.py @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +import sys; assert sys.version_info[0] >= 3, "Python 3 required." + from pyblake2 import blake2b import struct From bc6bc8a375e765a2d097e5216329eca77b425ce5 Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Fri, 17 Sep 2021 20:39:53 +0100 Subject: [PATCH 11/12] zc_utils.py: optionally enforce the MAX_SIZE limit (enforced by default). Signed-off-by: Daira Hopwood --- zc_utils.py | 69 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 27 deletions(-) diff --git a/zc_utils.py b/zc_utils.py index 13e9fa9..1fa2c58 100755 --- a/zc_utils.py +++ b/zc_utils.py @@ -3,7 +3,10 @@ import sys; assert sys.version_info[0] >= 3, "Python 3 required." import struct -def write_compact_size(n): +MAX_SIZE = 0x2000000 + +def write_compact_size(n, allow_u64=False): + assert allow_u64 or n <= MAX_SIZE if n < 253: return struct.pack('B', n) elif n <= 0xFFFF: @@ -13,7 +16,12 @@ def write_compact_size(n): else: return struct.pack('B', 255) + struct.pack('= 1 b = rest[0] if b < 253: @@ -35,36 +43,43 @@ def parse_compact_size(rest): return (n, rest[9:]) -def assert_parse_fails(encoding): +def assert_parse_fails(encoding, allow_u64): try: - parse_compact_size(encoding) + parse_compact_size(encoding, allow_u64) except AssertionError: pass else: raise AssertionError("parse_compact_size(%r) failed to raise AssertionError" % (encoding,)) -def test_round_trip(n, encoding): - assert write_compact_size(n) == encoding - assert parse_compact_size(encoding) == (n, b'') - assert parse_compact_size(encoding + b'*') == (n, b'*') - assert_parse_fails(encoding[:-1]) +def test_round_trip(n, encoding, allow_u64): + assert write_compact_size(n, allow_u64) == encoding + assert parse_compact_size(encoding, allow_u64) == (n, b'') + assert parse_compact_size(encoding + b'*', allow_u64) == (n, b'*') + assert_parse_fails(encoding[:-1], allow_u64) -test_round_trip(0, b'\x00') -test_round_trip(1, b'\x01') -test_round_trip(252, b'\xFC') -test_round_trip(253, b'\xFD\xFD\x00') -test_round_trip(254, b'\xFD\xFE\x00') -test_round_trip(255, b'\xFD\xFF\x00') -test_round_trip(256, b'\xFD\x00\x01') -test_round_trip(0xFFFE, b'\xFD\xFE\xFF') -test_round_trip(0xFFFF, b'\xFD\xFF\xFF') -test_round_trip(0x010000, b'\xFE\x00\x00\x01\x00') -test_round_trip(0x010001, b'\xFE\x01\x00\x01\x00') -test_round_trip(0xFFFFFFFE, b'\xFE\xFE\xFF\xFF\xFF') -test_round_trip(0xFFFFFFFF, b'\xFE\xFF\xFF\xFF\xFF') -test_round_trip(0x0100000000, b'\xFF\x00\x00\x00\x00\x01\x00\x00\x00') -test_round_trip(0xFFFFFFFFFFFFFFFF, b'\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF') +for allow_u64 in (False, True): + test_round_trip(0, b'\x00', allow_u64) + test_round_trip(1, b'\x01', allow_u64) + test_round_trip(252, b'\xFC', allow_u64) + test_round_trip(253, b'\xFD\xFD\x00', allow_u64) + test_round_trip(254, b'\xFD\xFE\x00', allow_u64) + test_round_trip(255, b'\xFD\xFF\x00', allow_u64) + test_round_trip(256, b'\xFD\x00\x01', allow_u64) + test_round_trip(0xFFFE, b'\xFD\xFE\xFF', allow_u64) + test_round_trip(0xFFFF, b'\xFD\xFF\xFF', allow_u64) + test_round_trip(0x010000, b'\xFE\x00\x00\x01\x00', allow_u64) + test_round_trip(0x010001, b'\xFE\x01\x00\x01\x00', allow_u64) + test_round_trip(0x02000000, b'\xFE\x00\x00\x00\x02', allow_u64) -assert_parse_fails(b'\xFD\xFC\x00') -assert_parse_fails(b'\xFE\xFF\xFF\x00\x00') -assert_parse_fails(b'\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00') + assert_parse_fails(b'\xFD\xFC\x00', allow_u64) + assert_parse_fails(b'\xFE\xFF\xFF\x00\x00', allow_u64) + assert_parse_fails(b'\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00', allow_u64) + +assert_parse_fails(b'\xFE\x01\x00\x00\x02', False) +assert_parse_fails(b'\xFF\x00\x00\x00\x00\x01\x00\x00\x00', False) +assert_parse_fails(b'\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF', False) + +test_round_trip(0xFFFFFFFE, b'\xFE\xFE\xFF\xFF\xFF', True) +test_round_trip(0xFFFFFFFF, b'\xFE\xFF\xFF\xFF\xFF', True) +test_round_trip(0x0100000000, b'\xFF\x00\x00\x00\x00\x01\x00\x00\x00', True) +test_round_trip(0xFFFFFFFFFFFFFFFF, b'\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF', True) From 3838e2514d88f0f8068c39829ea29c51542a1a88 Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Fri, 17 Sep 2021 20:40:48 +0100 Subject: [PATCH 12/12] Apply suggestion for the type of jumbled_hash. Co-authored-by: str4d --- f4jumble_long.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/f4jumble_long.py b/f4jumble_long.py index 2b1553c..f8af499 100755 --- a/f4jumble_long.py +++ b/f4jumble_long.py @@ -31,7 +31,7 @@ def main(): 'f4jumble_long', ( ('length', 'usize'), - ('jumbled_hash', 'Vec'), + ('jumbled_hash', '[u8; 64]'), ), hashed_test_vectors, )