def sign_( msg_hash: Octets, prv_key: PrvKey, nonce: Optional[PrvKey] = None, lower_s: bool = True, ec: Curve = secp256k1, hf: HashF = sha256, ) -> Sig: """Sign a hf_len bytes message according to ECDSA signature algorithm. If the deterministic nonce is not provided, the RFC6979 specification is used. """ # the message msg_hash: a hf_len array hf_len = hf().digest_size msg_hash = bytes_from_octets(msg_hash, hf_len) # the secret key q: an integer in the range 1..n-1. # SEC 1 v.2 section 3.2.1 q = int_from_prv_key(prv_key, ec) # the challenge c = challenge_(msg_hash, ec, hf) # 4, 5 # nonce: an integer in the range 1..n-1. if nonce is None: nonce = _rfc6979_(c, q, ec, hf) # 1 else: nonce = int_from_prv_key(nonce, ec) # second part delegated to helper function return _sign_(c, q, nonce, lower_s, ec)
def rfc6979_( msg_hash: Octets, prv_key: PrvKey, ec: Curve = secp256k1, hf: HashF = sha256 ) -> int: """Return a deterministic ephemeral key following RFC 6979. see https://tools.ietf.org/html/rfc6979 section 3.2 """ c = challenge_(msg_hash, ec, hf) q = int_from_prv_key(prv_key, ec) return _rfc6979_(c, q, ec, hf)
def gen_keys(prv_key: Optional[PrvKey] = None, ec: Curve = secp256k1) -> Tuple[int, Point]: "Return a private/public (int, Point) key-pair." if prv_key is None: # q in the range [1, ec.n-1] q = 1 + secrets.randbelow(ec.n - 1) else: q = int_from_prv_key(prv_key, ec) QJ = _mult(q, ec.GJ, ec) Q = ec.aff_from_jac(QJ) return q, Q
def gen_keys_(prv_key: Optional[PrvKey] = None, ec: Curve = secp256k1) -> Tuple[int, int, JacPoint]: "Return a BIP340 private/public (int, JacPoint) key-pair." if prv_key is None: q = 1 + secrets.randbelow(ec.n - 1) else: q = int_from_prv_key(prv_key, ec) QJ = _mult(q, ec.GJ, ec) x_Q, y_Q = ec.aff_from_jac(QJ) if y_Q % 2: q = ec.n - q QJ = ec.negate_jac(QJ) return q, x_Q, QJ
def ssa_commit_sign_( commit_hash: Octets, msg_hash: Octets, prv_key: PrvKey, nonce: Optional[PrvKey] = None, ec: Curve = secp256k1, hf: HashF = sha256, ) -> Tuple[ssa.Sig, Point]: "Include a commitment inside an EC SSA signature." nonce = (ssa.det_nonce_(msg_hash, prv_key, aux=None, ec=ec, hf=hf) if nonce is None else int_from_prv_key(nonce, ec)) R = mult(nonce, ec.G, ec) tweaked_nonce = (nonce + _tweak(commit_hash, R, ec, hf)) % ec.n tweaked_sig = ssa.sign_(msg_hash, prv_key, tweaked_nonce, ec, hf) return tweaked_sig, R
def output_prvkey( internal_prvkey: PrvKey, script_tree: Optional[TaprootScriptTree] = None, ec: Curve = secp256k1, ) -> int: internal_prvkey = int_from_prv_key(internal_prvkey) P = mult(internal_prvkey) if script_tree: _, h = tree_helper(script_tree) else: h = b"" has_even_y = ec.y_even(P[0]) == P[1] internal_prvkey = internal_prvkey if has_even_y else ec.n - internal_prvkey t = int.from_bytes(tagged_hash(b"TapTweak", P[0].to_bytes(32, "big") + h), "big") # edge case that cannot be reproduced in the test suite if t >= ec.n: raise BTClibValueError("Invalid script tree hash") # pragma: no cover return (internal_prvkey + t) % ec.n
def test_from_prv_key() -> None: secp256r1 = CURVES["secp256r1"] m_c = (q, "mainnet", True) m_unc = (q, "mainnet", False) t_c = (q, "testnet", True) t_unc = (q, "testnet", False) for prv_key in [q, *plain_prv_keys]: assert q == int_from_prv_key(prv_key) assert q == int_from_prv_key(prv_key, secp256r1) assert m_c == prv_keyinfo_from_prv_key(prv_key) assert m_c == prv_keyinfo_from_prv_key(prv_key, "mainnet") assert m_c == prv_keyinfo_from_prv_key(prv_key, "mainnet", compressed=True) assert m_c == prv_keyinfo_from_prv_key(prv_key, compressed=True) assert m_unc == prv_keyinfo_from_prv_key(prv_key, "mainnet", compressed=False) assert m_unc == prv_keyinfo_from_prv_key(prv_key, compressed=False) assert t_c == prv_keyinfo_from_prv_key(prv_key, "testnet") assert t_c == prv_keyinfo_from_prv_key(prv_key, "testnet", compressed=True) assert t_unc == prv_keyinfo_from_prv_key(prv_key, "testnet", compressed=False) for prv_key2 in [xprv_data, *compressed_prv_keys]: assert q == int_from_prv_key(prv_key2) with pytest.raises(BTClibValueError): int_from_prv_key(prv_key2, secp256r1) assert m_c == prv_keyinfo_from_prv_key(prv_key2) assert m_c == prv_keyinfo_from_prv_key(prv_key2, "mainnet") assert m_c == prv_keyinfo_from_prv_key(prv_key2, "mainnet", compressed=True) assert m_c == prv_keyinfo_from_prv_key(prv_key2, compressed=True) with pytest.raises(BTClibValueError): prv_keyinfo_from_prv_key(prv_key2, "mainnet", compressed=False) with pytest.raises(BTClibValueError): prv_keyinfo_from_prv_key(prv_key2, compressed=False) with pytest.raises(BTClibValueError): prv_keyinfo_from_prv_key(prv_key2, "testnet") with pytest.raises(BTClibValueError): prv_keyinfo_from_prv_key(prv_key2, "testnet", compressed=True) with pytest.raises(BTClibValueError): prv_keyinfo_from_prv_key(prv_key2, "testnet", compressed=False) for prv_key3 in uncompressed_prv_keys: assert q == int_from_prv_key(prv_key3) with pytest.raises(BTClibValueError): int_from_prv_key(prv_key3, secp256r1) assert m_unc == prv_keyinfo_from_prv_key(prv_key3) assert m_unc == prv_keyinfo_from_prv_key(prv_key3, "mainnet") with pytest.raises(BTClibValueError): prv_keyinfo_from_prv_key(prv_key3, "mainnet", compressed=True) with pytest.raises(BTClibValueError): prv_keyinfo_from_prv_key(prv_key3, compressed=True) assert m_unc == prv_keyinfo_from_prv_key(prv_key3, "mainnet", compressed=False) assert m_unc == prv_keyinfo_from_prv_key(prv_key3, compressed=False) with pytest.raises(BTClibValueError): prv_keyinfo_from_prv_key(prv_key3, "testnet") with pytest.raises(BTClibValueError): prv_keyinfo_from_prv_key(prv_key3, "testnet", compressed=True) with pytest.raises(BTClibValueError): prv_keyinfo_from_prv_key(prv_key3, "testnet", compressed=False) for prv_key4 in [xprv_data, *net_aware_prv_keys]: assert q == int_from_prv_key(prv_key4) with pytest.raises(BTClibValueError): int_from_prv_key(prv_key4, secp256r1) assert prv_keyinfo_from_prv_key(prv_key4) in (m_c, m_unc) assert prv_keyinfo_from_prv_key(prv_key4, "mainnet") in (m_c, m_unc) with pytest.raises(BTClibValueError): prv_keyinfo_from_prv_key(prv_key4, "testnet") for prv_key5 in [q, *net_unaware_prv_keys]: assert q == int_from_prv_key(prv_key5) assert q == int_from_prv_key(prv_key5, secp256r1) assert prv_keyinfo_from_prv_key(prv_key5) in (m_c, m_unc) assert prv_keyinfo_from_prv_key(prv_key5, "mainnet") in (m_c, m_unc) assert prv_keyinfo_from_prv_key(prv_key5, "testnet") in (t_c, t_unc) for invalid_prv_key in [q0, qn, xprv0_data, xprvn_data, *invalid_prv_keys]: with pytest.raises(BTClibValueError): int_from_prv_key(invalid_prv_key) # type: ignore with pytest.raises(BTClibValueError): prv_keyinfo_from_prv_key(invalid_prv_key) # type: ignore for not_a_prv_key in [ q0, qn, xprv0_data, xprvn_data, INF, INF_xpub_data, *not_a_prv_keys, Q, *plain_pub_keys, xpub_data, *compressed_pub_keys, *uncompressed_pub_keys, ]: with pytest.raises(BTClibValueError): int_from_prv_key(not_a_prv_key) # type: ignore with pytest.raises(BTClibValueError): prv_keyinfo_from_prv_key(not_a_prv_key) # type: ignore