def check_output_pubkey(q: Octets, script: Octets, control: Octets, ec: Curve = secp256k1) -> bool: q = bytes_from_octets(q) script = bytes_from_octets(script) control = bytes_from_octets(control) if len(control) > 4129: # 33 + 32 * 128 raise BTClibValueError("Control block too long") m = (len(control) - 33) // 32 if len(control) != 33 + 32 * m: raise BTClibValueError("Invalid control block length") leaf_version = control[0] & 0xFE preimage = leaf_version.to_bytes(1, "big") + var_bytes.serialize(script) k = tagged_hash(b"TapLeaf", preimage) for j in range(m): e = control[33 + 32 * j:65 + 32 * j] if k < e: k = tagged_hash(b"TapBranch", k + e) else: k = tagged_hash(b"TapBranch", e + k) p_bytes = control[1:33] t_bytes = tagged_hash(b"TapTweak", p_bytes + k) p = int.from_bytes(p_bytes, "big") t = int.from_bytes(t_bytes, "big") # edge case that cannot be reproduced in the test suite if t >= ec.n: raise BTClibValueError("Invalid script tree hash") # pragma: no cover P = (p, secp256k1.y_even(p)) Q = secp256k1.add(P, mult(t)) return Q[0] == int.from_bytes(q, "big") and control[0] & 1 == Q[1] % 2
def test_double_mult() -> None: H = second_generator(secp256k1) G = secp256k1.G # 0*G + 1*H T = double_mult(1, H, 0, G) assert T == H T = multi_mult([1, 0], [H, G]) assert T == H # 0*G + 2*H exp = mult(2, H) T = double_mult(2, H, 0, G) assert T == exp T = multi_mult([2, 0], [H, G]) assert T == exp # 0*G + 3*H exp = mult(3, H) T = double_mult(3, H, 0, G) assert T == exp T = multi_mult([3, 0], [H, G]) assert T == exp # 1*G + 0*H T = double_mult(0, H, 1, G) assert T == G T = multi_mult([0, 1], [H, G]) assert T == G # 2*G + 0*H exp = mult(2, G) T = double_mult(0, H, 2, G) assert T == exp T = multi_mult([0, 2], [H, G]) assert T == exp # 3*G + 0*H exp = mult(3, G) T = double_mult(0, H, 3, G) assert T == exp T = multi_mult([0, 3], [H, G]) assert T == exp # 0*G + 5*H exp = mult(5, H) T = double_mult(5, H, 0, G) assert T == exp T = multi_mult([5, 0], [H, G]) assert T == exp # 0*G - 5*H exp = mult(-5, H) T = double_mult(-5, H, 0, G) assert T == exp T = multi_mult([-5, 0], [H, G]) assert T == exp # 1*G - 5*H exp = secp256k1.add(G, T) T = double_mult(-5, H, 1, G) assert T == exp
mprvkey = 1 + secrets.randbelow(ec.n - 1) print(f"\nmaster prvkey: {hex(mprvkey).upper()}") # Master Pubkey: mpubkey = mult(mprvkey, ec.G) print(f"Master Pubkey: {hex(mpubkey[0]).upper()}") print(f" {hex(mpubkey[1]).upper()}") r = secrets.randbits(ec.nlen) print(f"\npublic random number: {hex(r).upper()}") rbytes = r.to_bytes(ec.nsize, "big") nKeys = 3 for i in range(nKeys): ibytes = i.to_bytes(ec.nsize, "big") hd = hf(ibytes + rbytes).digest() offset = int_from_bits(hd, ec.nlen) % ec.n q = (mprvkey + offset) % ec.n Q = mult(q, ec.G, ec) print(f"\nprvkey #{i}: {hex(q).upper()}") print(f"Pubkey #{i}: {hex(Q[0]).upper()}") print(f" {hex(Q[1]).upper()}") # Pubkeys could also be calculated without using prvkeys for i in range(nKeys): ibytes = i.to_bytes(ec.nsize, "big") hd = hf(ibytes + rbytes).digest() offset = int_from_bits(hd, ec.nlen) % ec.n Q = ec.add(mpubkey, mult(offset, ec.G, ec)) assert Q == mult((mprvkey + offset) % ec.n, ec.G, ec)