def test_sign_schnorr(self): pk = PrivateKey(randint(1, N)) msg = int_to_big_endian(randint(1, N), 32) sig = pk.sign_schnorr(msg, aux=b"\x00" * 32) self.assertTrue(pk.point.verify_schnorr(msg, sig)) # tweak tweak = randint(1, N) tweak_point = pk.tweaked(tweak).point k = randint(1, N) r = k * G if r.parity: k = N - k r = k * G message = r.bip340() + tweak_point.bip340() + msg challenge = big_endian_to_int(hash_challenge(message)) % N if pk.point.parity == tweak_point.parity: secret = pk.secret else: secret = -pk.secret s = (k + challenge * secret) % N if tweak_point.parity: s = (s - challenge * tweak) % N else: s = (s + challenge * tweak) % N sig = SchnorrSignature.parse(r.bip340() + int_to_big_endian(s, 32)) self.assertTrue(tweak_point.verify_schnorr(msg, sig))
def verify_schnorr(self, msg, schnorr_sig): if self.parity: point = -1 * self else: point = self if schnorr_sig.r.x is None: return False message = schnorr_sig.r.bip340() + point.bip340() + msg challenge = big_endian_to_int(hash_challenge(message)) % N result = -challenge * point + schnorr_sig.s if result.x is None: return False if result.parity: return False return result.bip340() == schnorr_sig.r.bip340()
def sign(self, private_key, k, r, sig_hash, tweak=0): tweak_point = self.get_tweak_point(tweak) msg = r.bip340() + tweak_point.bip340() + sig_hash challenge = big_endian_to_int(hash_challenge(msg)) % N h_i = self.coef_lookup[private_key.point.bip340()] c_i = h_i * challenge % N if r.parity == tweak_point.parity: k_real = k else: k_real = -k if self.point.parity == private_key.point.parity: secret = private_key.secret else: secret = -private_key.secret return (k_real + c_i * secret) % N
def get_signature(self, s_sum, r, sig_hash, tweak=0): tweak_point = self.get_tweak_point(tweak) if tweak: msg = r.bip340() + tweak_point.bip340() + sig_hash challenge = big_endian_to_int(hash_challenge(msg)) % N if tweak_point.parity: s = (-s_sum - challenge * tweak) % N else: s = (s_sum + challenge * tweak) % N else: s = s_sum % N s_raw = int_to_big_endian(s, 32) sig = r.bip340() + s_raw schnorrsig = SchnorrSignature.parse(sig) if not tweak_point.verify_schnorr(sig_hash, schnorrsig): raise ValueError("Invalid signature") return schnorrsig
def sign_schnorr(self, msg, aux): if self.point.parity: d = N - self.secret else: d = self.secret if len(msg) != 32: raise ValueError("msg needs to be 32 bytes") if len(aux) != 32: raise ValueError("aux needs to be 32 bytes") t = xor_bytes(int_to_big_endian(d, 32), hash_aux(aux)) k = big_endian_to_int(hash_nonce(t + self.point.bip340() + msg)) % N r = k * G if r.parity: k = N - k r = k * G message = r.bip340() + self.point.bip340() + msg e = big_endian_to_int(hash_challenge(message)) % N s = (k + e * d) % N sig = SchnorrSignature(r, s) if not self.point.verify_schnorr(msg, sig): raise RuntimeError("Bad Signature") return sig