mirror of
https://github.com/bitcoin/bips.git
synced 2026-02-09 15:23:09 +00:00
* Add Chaincode Delegation BIP * Update license to BSD-3-Clause and expand blinded signing documentation * Address initial PR comments * Update with BIP number assignment * Fix delegator_sign test vector * Upgrade secp256k1lab and add license file - Upgrade vendored secp256k1lab to commit a265da1 (adds type annotations) - Add COPYING file to satisfy MIT license requirements - Document secp256k1lab commit reference in BIP text * Fix type checker and linter issues in reference implementation - Fix TweakContext to use Scalar types for gacc/tacc - Replace HashFunction enum with Callable type alias - Fix bytearray to bytes conversion in blind_sign - Move imports to top of file - Fix boolean comparison style (use 'not' instead of '== False') - Add proper type annotations and casts for dict handling - Remove unused imports and type ignore comments * Address PR review comments on terminology and clarity - Add intro explaining delegation naming (chain code is delegated, not signing authority) - Reorder terminology to list Delegator before Delegatee - Replace "quorum" with clearer "can co-sign for UTXOs" language - Clarify derivation constraints in terms of delegatee's extended key - Rename "Delegatee Signing" section to "Signing Modes" - Fix "delegatee can apply" to "delegator can produce" (line 112) - Replace undefined "caller" with "delegatee" (line 173) - Clarify "Change outputs" to "Tweaks for change outputs" (line 98) - Add note that message is separate from CCD bundle - Add note on application-specific verification (addresses, amounts) - Add transition sentence clarifying non-concurrent protocol scope * Add changelog entry for 0.1.3 * Fix header: use Authors (plural) for multiple authors * Fix BIP header format for CI compliance - Change Type from 'Standards Track' to 'Specification' (valid type) - Change 'Created' to 'Assigned' (correct field name per BIP format) - Change 'Post-History' to 'Discussion' (recognized field in buildtable.pl) * Apply suggestion from @murchandamus --------- Co-authored-by: Jesse Posner <jesse.posner@gmail.com>
74 lines
2.4 KiB
Python
74 lines
2.4 KiB
Python
# The following functions are based on the BIP 340 reference implementation:
|
|
# https://github.com/bitcoin/bips/blob/master/bip-0340/reference.py
|
|
|
|
from .secp256k1 import FE, GE, G
|
|
from .util import int_from_bytes, bytes_from_int, xor_bytes, tagged_hash
|
|
|
|
|
|
def pubkey_gen(seckey: bytes) -> bytes:
|
|
d0 = int_from_bytes(seckey)
|
|
if not (1 <= d0 <= GE.ORDER - 1):
|
|
raise ValueError("The secret key must be an integer in the range 1..n-1.")
|
|
P = d0 * G
|
|
assert not P.infinity
|
|
return P.to_bytes_xonly()
|
|
|
|
|
|
def schnorr_sign(
|
|
msg: bytes, seckey: bytes, aux_rand: bytes, tag_prefix: str = "BIP0340"
|
|
) -> bytes:
|
|
d0 = int_from_bytes(seckey)
|
|
if not (1 <= d0 <= GE.ORDER - 1):
|
|
raise ValueError("The secret key must be an integer in the range 1..n-1.")
|
|
if len(aux_rand) != 32:
|
|
raise ValueError("aux_rand must be 32 bytes instead of %i." % len(aux_rand))
|
|
P = d0 * G
|
|
assert not P.infinity
|
|
d = d0 if P.has_even_y() else GE.ORDER - d0
|
|
t = xor_bytes(bytes_from_int(d), tagged_hash(tag_prefix + "/aux", aux_rand))
|
|
k0 = (
|
|
int_from_bytes(tagged_hash(tag_prefix + "/nonce", t + P.to_bytes_xonly() + msg))
|
|
% GE.ORDER
|
|
)
|
|
if k0 == 0:
|
|
raise RuntimeError("Failure. This happens only with negligible probability.")
|
|
R = k0 * G
|
|
assert not R.infinity
|
|
k = k0 if R.has_even_y() else GE.ORDER - k0
|
|
e = (
|
|
int_from_bytes(
|
|
tagged_hash(
|
|
tag_prefix + "/challenge", R.to_bytes_xonly() + P.to_bytes_xonly() + msg
|
|
)
|
|
)
|
|
% GE.ORDER
|
|
)
|
|
sig = R.to_bytes_xonly() + bytes_from_int((k + e * d) % GE.ORDER)
|
|
assert schnorr_verify(msg, P.to_bytes_xonly(), sig, tag_prefix=tag_prefix)
|
|
return sig
|
|
|
|
|
|
def schnorr_verify(
|
|
msg: bytes, pubkey: bytes, sig: bytes, tag_prefix: str = "BIP0340"
|
|
) -> bool:
|
|
if len(pubkey) != 32:
|
|
raise ValueError("The public key must be a 32-byte array.")
|
|
if len(sig) != 64:
|
|
raise ValueError("The signature must be a 64-byte array.")
|
|
try:
|
|
P = GE.from_bytes_xonly(pubkey)
|
|
except ValueError:
|
|
return False
|
|
r = int_from_bytes(sig[0:32])
|
|
s = int_from_bytes(sig[32:64])
|
|
if (r >= FE.SIZE) or (s >= GE.ORDER):
|
|
return False
|
|
e = (
|
|
int_from_bytes(tagged_hash(tag_prefix + "/challenge", sig[0:32] + pubkey + msg))
|
|
% GE.ORDER
|
|
)
|
|
R = s * G - e * P
|
|
if R.infinity or (not R.has_even_y()) or (R.x != r):
|
|
return False
|
|
return True
|