Changeset View
Changeset View
Standalone View
Standalone View
test/functional/test_framework/key.py
#!/usr/bin/env python3 | #!/usr/bin/env python3 | ||||
# Copyright (c) 2019 Pieter Wuille | # Copyright (c) 2019 Pieter Wuille | ||||
# Copyright (c) 2019-2020 The Bitcoin developers | |||||
"""Test-only secp256k1 elliptic curve implementation | """Test-only secp256k1 elliptic curve implementation | ||||
WARNING: This code is slow, uses bad randomness, does not properly protect | WARNING: This code is slow, uses bad randomness, does not properly protect | ||||
keys, and is trivially vulnerable to side channel attacks. Do not use for | keys, and is trivially vulnerable to side channel attacks. Do not use for | ||||
anything but tests. | anything but tests. | ||||
""" | """ | ||||
import hashlib | |||||
import random | import random | ||||
def modinv(a, n): | def modinv(a, n): | ||||
"""Compute the modular inverse of a modulo n | """Compute the modular inverse of a modulo n | ||||
See https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Modular_integers | See https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Modular_integers | ||||
""" | """ | ||||
▲ Show 20 Lines • Show All 277 Lines • ▼ Show 20 Lines | def verify_ecdsa(self, sig, msg, low_s=True): | ||||
w = modinv(s, SECP256K1_ORDER) | w = modinv(s, SECP256K1_ORDER) | ||||
u1 = z * w % SECP256K1_ORDER | u1 = z * w % SECP256K1_ORDER | ||||
u2 = r * w % SECP256K1_ORDER | u2 = r * w % SECP256K1_ORDER | ||||
R = SECP256K1.affine(SECP256K1.mul([(SECP256K1_G, u1), (self.p, u2)])) | R = SECP256K1.affine(SECP256K1.mul([(SECP256K1_G, u1), (self.p, u2)])) | ||||
if R is None or R[0] != r: | if R is None or R[0] != r: | ||||
return False | return False | ||||
return True | return True | ||||
def verify_schnorr(self, sig, msg32): | |||||
assert self.is_valid | |||||
assert len(sig) == 64 | |||||
assert len(msg32) == 32 | |||||
Rx = sig[:32] | |||||
s = int.from_bytes(sig[32:], 'big') | |||||
e = int.from_bytes( | |||||
hashlib.sha256( | |||||
Rx + | |||||
self.get_bytes() + | |||||
msg32).digest(), | |||||
'big') | |||||
nege = SECP256K1_ORDER - e | |||||
R = SECP256K1.affine(SECP256K1.mul([(SECP256K1_G, s), (self.p, nege)])) | |||||
if R is None: | |||||
return False | |||||
if jacobi_symbol(R[1], SECP256K1.p) == -1: | |||||
return False | |||||
return R[0] == int.from_bytes(Rx, 'big') | |||||
class ECKey(): | class ECKey(): | ||||
"""A secp256k1 private key""" | """A secp256k1 private key""" | ||||
def __init__(self): | def __init__(self): | ||||
self.valid = False | self.valid = False | ||||
def set(self, secret, compressed): | def set(self, secret, compressed): | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | def sign_ecdsa(self, msg, low_s=True): | ||||
s = (modinv(k, SECP256K1_ORDER) * (z + self.secret * r)) % SECP256K1_ORDER | s = (modinv(k, SECP256K1_ORDER) * (z + self.secret * r)) % SECP256K1_ORDER | ||||
if low_s and s > SECP256K1_ORDER_HALF: | if low_s and s > SECP256K1_ORDER_HALF: | ||||
s = SECP256K1_ORDER - s | s = SECP256K1_ORDER - s | ||||
rb = r.to_bytes((r.bit_length() + 8) // 8, 'big') | rb = r.to_bytes((r.bit_length() + 8) // 8, 'big') | ||||
sb = s.to_bytes((s.bit_length() + 8) // 8, 'big') | sb = s.to_bytes((s.bit_length() + 8) // 8, 'big') | ||||
return b'\x30' + \ | return b'\x30' + \ | ||||
bytes([4 + len(rb) + len(sb), 2, len(rb)]) + \ | bytes([4 + len(rb) + len(sb), 2, len(rb)]) + \ | ||||
rb + bytes([2, len(sb)]) + sb | rb + bytes([2, len(sb)]) + sb | ||||
def sign_schnorr(self, msg32): | |||||
"""Create Schnorr signature (BIP-Schnorr convention).""" | |||||
assert self.valid | |||||
assert len(msg32) == 32 | |||||
pubkey = self.get_pubkey() | |||||
assert pubkey.is_valid | |||||
k = random.randrange(1, SECP256K1_ORDER) | |||||
R = SECP256K1.affine(SECP256K1.mul([(SECP256K1_G, k)])) | |||||
if jacobi_symbol(R[1], SECP256K1.p) == -1: | |||||
k = SECP256K1_ORDER - k | |||||
Rx = R[0].to_bytes(32, 'big') | |||||
e = int.from_bytes( | |||||
hashlib.sha256( | |||||
Rx + | |||||
pubkey.get_bytes() + | |||||
msg32).digest(), | |||||
'big') | |||||
s = (k + e * int.from_bytes(self.get_bytes(), 'big')) % SECP256K1_ORDER | |||||
sig = Rx + s.to_bytes(32, 'big') | |||||
assert pubkey.verify_schnorr(sig, msg32) | |||||
return sig |