def ecssa_verify_raw(m: bytes, ssasig: Tuple[int, int], pub: Tuple[int, int], hasher) -> bool: R_x, s = ssasig[0].to_bytes(32, 'big'), ssasig[1] e = hasher(R_x + m).digest() e = int_from_hash(e, ec.order) if e == 0 or e >= ec.order: # invalid e value return False R = ec.pointAdd(ec.pointMultiply(e, pub), ec.pointMultiply(s)) if R[1] % 2 == 1: # R.y odd return False return R[0] == ssasig[0]
def ecssa_pubkey_recovery_raw(m: bytes, ssasig: Tuple[int, int], hasher=sha256) -> Tuple[int, int]: R_x, s = ssasig R = (R_x, ec.y(R_x, 0)) R_x = R_x.to_bytes(32, 'big') e = hasher(R_x + m).digest() e = int_from_hash(e, ec.order) assert e != 0 and e < ec.order, "invalid e value" e1 = mod_inv(e, ec.order) return ec.pointAdd(ec.pointMultiply(e1, R), ec.pointMultiply(-e1 * s % ec.order))
def verify_commit(receipt, c, hasher=sha256): ec.y(receipt[0], False) # receipt[0] is valid iif its y does exist ec.tuple_from_point(receipt[1]) # verify it is a good point w, R = receipt e = hasher(R[0].to_bytes(32, 'big') + c).digest() e = int_from_hash(e, ec.order) W = ec.pointAdd(R, ec.pointMultiply(e)) return w % ec.order == W[0] % ec.order
def tweak(k, c, hasher=sha256): """tweak kG returns: - point kG to tweak - tweaked private key k + h(kG||c), the corresponding pubkey is a commitment to kG, c """ R = ec.pointMultiply(k) e = hasher(R[0].to_bytes(32, 'big') + c).digest() e = int_from_hash(e, ec.order) return R, (e + k) % ec.order
def ecssa_sign_raw(m: bytes, prv: int, eph_prv: int, hasher=sha256) -> Tuple[int, int]: R = ec.pointMultiply(eph_prv) if R[1] % 2 == 1: eph_prv = ec.order - eph_prv # <=> R_y = ec_prime - R_y r = R[0] % ec.order # % ec.order ? e = hasher(R[0].to_bytes(32, 'big') + m).digest() e = int_from_hash(e, ec.order) assert e != 0 and e < ec.order, "sign fail" s = (eph_prv - e * prv) % ec.order return r, s
def det_wallet2(key, r, i): r_bytes = r.to_bytes(32, 'big') i_bytes = i.to_bytes(32, 'big') h_hex = sha256(i_bytes+r_bytes).hexdigest() h_int = int(h_hex, 16) try: prvkey = int_from_prvkey(key) return (prvkey + h_int) % ec.order except: pubkey = ec.tuple_from_point(key) return ec.pointAdd(pubkey, ec.pointMultiply(h_int)) raise ValueError("Invalid key")
def test_tuple_from_point(self): prv = 0xc28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d Pub = secp256k1.pointMultiply(prv) Pub_bytes = b'\x02' + Pub[0].to_bytes(32, "big") p2 = secp256k1.tuple_from_point(Pub_bytes) self.assertEqual(p2, Pub) Pub_hex_str = Pub_bytes.hex() p2 = secp256k1.tuple_from_point(Pub_hex_str) self.assertEqual(p2, Pub) Pub_bytes = b'\x04' + Pub[0].to_bytes(32, "big") + Pub[1].to_bytes(32, "big") p2 = secp256k1.tuple_from_point(Pub_bytes) self.assertEqual(p2, Pub) Pub_hex_str = Pub_bytes.hex() p2 = secp256k1.tuple_from_point(Pub_hex_str) self.assertEqual(p2, Pub)
def bip32_xpub_from_xprv(xprv): """Neutered Derivation (ND) Computation of the extended public key corresponding to an extended private key (“neutered” as it removes the ability to sign transactions) """ xprv = b58decode_check(xprv) assert len(xprv) == 78, "wrong length for decoded extended private key" assert xprv[45] == 0, "extended key is not a private one" i = PRIVATE.index(xprv[:4]) xpub = PUBLIC[i] # version # unchanged xpub += xprv[ 4: 5] # depth xpub += xprv[ 5: 9] # parent pubkey fingerprint xpub += xprv[ 9:13] # child index xpub += xprv[13:45] # chain code p = xprv[46:] P = ec.pointMultiply(p) xpub += ec.bytes_from_point(P, True) # public key return b58encode_check(xpub)
def bip32_ckd(xparentkey, index): """Child Key Derivation (CDK) Key derivation is normal if the extended parent key is public or child_index is less than 0x80000000. Key derivation is hardened if the extended parent key is private and child_index is not less than 0x80000000. """ if isinstance(index, int): index = index.to_bytes(4, 'big') elif isinstance(index, bytes) or isinstance(index, bytearray): assert len(index) == 4 else: raise TypeError("a 4 bytes int is required") xparent = b58decode_check(xparentkey) assert len(xparent) == 78, "wrong length for extended parent key" version = xparent[:4] xkey = version # version xkey += (xparent[4] + 1).to_bytes(1, 'big') # (increased) depth if (version in PUBLIC): assert xparent[45] in (2, 3), \ "version/key mismatch in extended parent key" Parent_bytes = xparent[45:] Parent = ec.tuple_from_point(Parent_bytes) xkey += h160(Parent_bytes)[:4] # parent pubkey fingerprint assert index[0] < 0x80, \ "no private/hardened derivation from pubkey" xkey += index # child index parent_chain_code = xparent[13:45] ## normal derivation h = HMAC(parent_chain_code, Parent_bytes + index, sha512).digest() xkey += h[32:] # chain code offset = int.from_bytes(h[:32], 'big') Offset = ec.pointMultiply(offset) Child = ec.pointAdd(Parent, Offset) Child_bytes = ec.bytes_from_point(Child, True) xkey += Child_bytes # public key elif (version in PRIVATE): assert xparent[45] == 0, "version/key mismatch in extended parent key" parent = int.from_bytes(xparent[46:], 'big') Parent = ec.pointMultiply(parent) Parent_bytes = ec.bytes_from_point(Parent, True) xkey += h160(Parent_bytes)[:4] # parent pubkey fingerprint xkey += index # child index parent_chain_code = xparent[13:45] if (index[0] < 0x80): ## normal derivation h = HMAC(parent_chain_code, Parent_bytes + index, sha512).digest() else: ## hardened derivation h = HMAC(parent_chain_code, xparent[45:] + index, sha512).digest() xkey += h[32:] # chain code offset = int.from_bytes(h[:32], 'big') child = (parent + offset) % ec.order child_bytes = b'\x00' + child.to_bytes(32, 'big') xkey += child_bytes # private key else: raise ValueError("invalid extended key version") return b58encode_check(xkey)
#!/usr/bin/env python3 from ellipticcurves import secp256k1 as ec from hashlib import sha256 print("\n*** EC:") print(ec) p = 0x18E14A7B6A307F426A94F8114701E7C8E774E7F9A47E2C2035DB29A206321725 p = p % ec.order print("\n*** Keys:") print("prvkey: ", hex(p)) P = ec.pointMultiply(p) print("PubKey:", "02" if (P[1] % 2 == 0) else "03", hex(P[0])) print("\n*** Message to be signed") msg1 = "Paolo is afraid of ephemeral random numbers" print(msg1) print("*** Hash of the message") h_bytes = sha256(msg1.encode()).digest() # hash(msg) must be transformed into an integer modulo ec.order: h1 = int.from_bytes(h_bytes, 'big') % ec.order assert h1 != 0 print(" h1:", hex(h1)) print("\n*** Signature") # ephemeral key k must be kept secret and never reused !!!!! # good choice: k = sha256(msg|p) # different for each msg, private because of p
def pubkey_from_prvkey(prvkey, compressed=True): P = ec.pointMultiply(prvkey) return ec.bytes_from_point(P, compressed)
def private_key_to_public_key(private_key, version=0x04): p = ec.pointMultiply(private_key) public_key = version+p[0]+p[1] return public_key
""" Deterministic Wallet (Type-2) """ from hashlib import sha256 from random import randint from ellipticcurves import secp256k1 as ec from wifaddress import int_from_prvkey # master prvkey mprvkey = randint(0, ec.order-1) print('\nmaster private key:', format(mprvkey, '#064x')) # Master Pubkey: mpubkey = ec.pointMultiply(mprvkey) print('Master Public Key:', format(mpubkey[0], '#064x')) print(' ', format(mpubkey[1], '#064x')) # public random number r = randint(0, 2**256-1) print('public ephemeral key:', format(r, '#064x')) p = [] h_int = [] nKeys = 3 r_bytes = r.to_bytes(32, 'big') for i in range(0, nKeys): i_bytes = i.to_bytes(32, 'big') h_hex = sha256(i_bytes+r_bytes).hexdigest() h_int.append(int(h_hex, 16))
#!/usr/bin/env python3 from ellipticcurves import secp256k1 as ec from hashlib import sha256 from numbertheory import mod_inv print("\n*** EC:") print(ec) p = 0x18E14A7B6A307F426A94F8114701E7C8E774E7F9A47E2C2035DB29A206321725 p = p % ec.order print("\n*** Keys:") print("prvkey: ", hex(p)) P = ec.pointMultiply(p, ec.G) print("PubKey:", "02" if (P[1] % 2 == 0) else "03", hex(P[0])) print("\n*** Message to be signed") msg1 = "Paolo is afraid of ephemeral random numbers" print(msg1) print("*** Hash of the message") h_bytes = sha256(msg1.encode()).digest() # hash(msg) must be transformed into an integer modulo ec.order: h1 = int.from_bytes(h_bytes, 'big') % ec.order assert h1 != 0 print(" h1:", hex(h1)) print("\n*** Signature") # ephemeral key k must be kept secret and never reused !!!!! # good choice: k = sha256(msg|p)
#!/usr/bin/env python3 from ellipticcurves import secp256k1 as ec from hashlib import sha256 from numbertheory import mod_inv print("\n*** EC:") print(ec) p = 0x18E14A7B6A307F426A94F8114701E7C8E774E7F9A47E2C2035DB29A206321725 p = p % ec.order print("\n*** Keys:") print("prvkey: ", hex(p)) P = ec.pointMultiply(p) print("PubKey:", "02" if (P[1] % 2 == 0) else "03", hex(P[0])) print("\n*** Message to be signed") msg1 = "Paolo is afraid of ephemeral random numbers" print(msg1) print("*** Hash of the message") h_bytes = sha256(msg1.encode()).digest() # hash(msg) must be transformed into an integer modulo ec.order: h1 = int.from_bytes(h_bytes, 'big') % ec.order assert h1 != 0 print(" h1:", hex(h1)) print("\n*** Signature") # ephemeral key k must be kept secret and never reused !!!!! # good choice: k = sha256(msg|p)
# ==master ext private key== # depth: 0x00 for master nodes, 0x01 for level-1 derived keys, ... depth = b'\x00' # This is ser32(i) for i in xi = xpar/i, with xi the key being serialized. (0x00000000 if master key) child_number = b'\x00\x00\x00\x00' # the fingerprint of the parent's public key (0x00000000 if master key) fingerprint = b'\x00\x00\x00\x00' idf = depth + fingerprint + child_number # master private key, master public key, chain code hashValue = HMAC(b"Bitcoin seed", seed.to_bytes(seed_bytes, 'big'), sha512).digest() p_bytes = hashValue[:32] p = int(p_bytes.hex(), 16) % ec.order p_bytes = b'\x00' + p.to_bytes(32, 'big') P = ec.pointMultiply(p, ec.G) P_bytes = (b'\x02' if (P[1] % 2 == 0) else b'\x03') + P[0].to_bytes(32, 'big') chain_code = hashValue[32:] #extended keys ext_prv = b58encode_check(xprv + idf + chain_code + p_bytes) print("\nm") print(ext_prv) ext_pub = b58encode_check(xpub + idf + chain_code + P_bytes) print("M") print(ext_pub) assert ext_prv == b"xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6", "failure" assert ext_pub == b"xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13", "failure" # ==first (0) hardened child== depth = b'\x01'
# ==master ext private key== # depth: 0x00 for master nodes, 0x01 for level-1 derived keys, ... depth = b'\x00' # This is ser32(i) for i in xi = xpar/i, with xi the key being serialized. (0x00000000 if master key) child_number = b'\x00\x00\x00\x00' # the fingerprint of the parent's public key (0x00000000 if master key) fingerprint = b'\x00\x00\x00\x00' idf = depth + fingerprint + child_number # master private key, master public key, chain code hashValue = HMAC(b"Bitcoin seed", seed.to_bytes(seed_bytes, 'big'), sha512).digest() p_bytes = hashValue[:32] p = int(p_bytes.hex(), 16) % ec.order p_bytes = b'\x00' + p.to_bytes(32, 'big') P = ec.pointMultiply(p) P_bytes = (b'\x02' if (P[1] % 2 == 0) else b'\x03') + P[0].to_bytes(32, 'big') chain_code = hashValue[32:] #extended keys ext_prv = b58encode_check(xprv + idf + chain_code + p_bytes) print("\nm") print(ext_prv) ext_pub = b58encode_check(xpub + idf + chain_code + P_bytes) print("M") print(ext_pub) assert ext_prv == b"xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6", "failure" assert ext_pub == b"xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13", "failure" # ==first (0) hardened child== depth = b'\x01'
#!/usr/bin/env python3 from ellipticcurves import secp256k1 as ec from hashlib import sha256 print("\n*** EC:") print(ec) p = 0x18E14A7B6A307F426A94F8114701E7C8E774E7F9A47E2C2035DB29A206321725 p = p % ec.order print("\n*** Keys:") print("prvkey: ", hex(p)) P = ec.pointMultiply(p, ec.G) print("PubKey:", "02" if (P[1] % 2 == 0) else "03", hex(P[0])) print("\n*** Message to be signed") msg1 = "Paolo is afraid of ephemeral random numbers" print(msg1) print("*** Hash of the message") h_bytes = sha256(msg1.encode()).digest() # hash(msg) must be transformed into an integer modulo ec.order: h1 = int.from_bytes(h_bytes, 'big') % ec.order assert h1 != 0 print(" h1:", hex(h1)) print("\n*** Signature") # ephemeral key k must be kept secret and never reused !!!!! # good choice: k = sha256(msg|p) # different for each msg, private because of p