mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-20 14:05:23 +01:00
tests: add deterministic signing mode to ECDSA
This does the following: * Adds a rfc6979 argument to test_framework/key.py's sign_ecdsa to select (deterministic) RFC6979-based nonce generation. * Add a flag in feature_taproot.py's framework called "deterministic". * Make the Schnorr signing in feature_taproot.py randomized by default, reverting to the old deterministic (aux_rnd=0x0000...00) behavior if the deterministic context flag is set. * Make the ECDSA signing in feature_taproot.py use RFC6979-based nonces when the deterministic context flag is set (keeping the old randomized behavior otherwise).
This commit is contained in:
parent
c98c53f20c
commit
ca83ffc2ea
2 changed files with 25 additions and 5 deletions
|
@ -253,14 +253,18 @@ def default_key_tweaked(ctx):
|
|||
def default_signature(ctx):
|
||||
"""Default expression for "signature": BIP340 signature or ECDSA signature depending on mode."""
|
||||
sighash = get(ctx, "sighash")
|
||||
deterministic = get(ctx, "deterministic")
|
||||
if get(ctx, "mode") == "taproot":
|
||||
key = get(ctx, "key_tweaked")
|
||||
flip_r = get(ctx, "flag_flip_r")
|
||||
flip_p = get(ctx, "flag_flip_p")
|
||||
return sign_schnorr(key, sighash, flip_r=flip_r, flip_p=flip_p)
|
||||
aux = bytes([0] * 32)
|
||||
if not deterministic:
|
||||
aux = random.getrandbits(256).to_bytes(32, 'big')
|
||||
return sign_schnorr(key, sighash, flip_r=flip_r, flip_p=flip_p, aux=aux)
|
||||
else:
|
||||
key = get(ctx, "key")
|
||||
return key.sign_ecdsa(sighash)
|
||||
return key.sign_ecdsa(sighash, rfc6979=deterministic)
|
||||
|
||||
def default_hashtype_actual(ctx):
|
||||
"""Default expression for "hashtype_actual": hashtype, unless mismatching SIGHASH_SINGLE in taproot."""
|
||||
|
@ -392,6 +396,8 @@ DEFAULT_CONTEXT = {
|
|||
"leaf": None,
|
||||
# The input arguments to provide to the executed script
|
||||
"inputs": [],
|
||||
# Use deterministic signing nonces
|
||||
"deterministic": False,
|
||||
|
||||
# == Parameters to be set before evaluation: ==
|
||||
# - mode: what spending style to use ("taproot", "witv0", or "legacy").
|
||||
|
|
|
@ -8,6 +8,7 @@ keys, and is trivially vulnerable to side channel attacks. Do not use for
|
|||
anything but tests."""
|
||||
import csv
|
||||
import hashlib
|
||||
import hmac
|
||||
import os
|
||||
import random
|
||||
import unittest
|
||||
|
@ -326,6 +327,16 @@ def generate_privkey():
|
|||
"""Generate a valid random 32-byte private key."""
|
||||
return random.randrange(1, SECP256K1_ORDER).to_bytes(32, 'big')
|
||||
|
||||
def rfc6979_nonce(key):
|
||||
"""Compute signing nonce using RFC6979."""
|
||||
v = bytes([1] * 32)
|
||||
k = bytes([0] * 32)
|
||||
k = hmac.new(k, v + b"\x00" + key, 'sha256').digest()
|
||||
v = hmac.new(k, v, 'sha256').digest()
|
||||
k = hmac.new(k, v + b"\x01" + key, 'sha256').digest()
|
||||
v = hmac.new(k, v, 'sha256').digest()
|
||||
return hmac.new(k, v, 'sha256').digest()
|
||||
|
||||
class ECKey():
|
||||
"""A secp256k1 private key"""
|
||||
|
||||
|
@ -368,15 +379,18 @@ class ECKey():
|
|||
ret.compressed = self.compressed
|
||||
return ret
|
||||
|
||||
def sign_ecdsa(self, msg, low_s=True):
|
||||
def sign_ecdsa(self, msg, low_s=True, rfc6979=False):
|
||||
"""Construct a DER-encoded ECDSA signature with this key.
|
||||
|
||||
See https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm for the
|
||||
ECDSA signer algorithm."""
|
||||
assert(self.valid)
|
||||
z = int.from_bytes(msg, 'big')
|
||||
# Note: no RFC6979, but a simple random nonce (some tests rely on distinct transactions for the same operation)
|
||||
k = random.randrange(1, SECP256K1_ORDER)
|
||||
# Note: no RFC6979 by default, but a simple random nonce (some tests rely on distinct transactions for the same operation)
|
||||
if rfc6979:
|
||||
k = int.from_bytes(rfc6979_nonce(self.secret.to_bytes(32, 'big') + msg), 'big')
|
||||
else:
|
||||
k = random.randrange(1, SECP256K1_ORDER)
|
||||
R = SECP256K1.affine(SECP256K1.mul([(SECP256K1_G, k)]))
|
||||
r = R[0] % SECP256K1_ORDER
|
||||
s = (modinv(k, SECP256K1_ORDER) * (z + self.secret * r)) % SECP256K1_ORDER
|
||||
|
|
Loading…
Add table
Reference in a new issue