From 1c6ac0c4cf1f39ea806b8594d6060b6d52fd1439 Mon Sep 17 00:00:00 2001 From: siv2r Date: Wed, 17 Jul 2024 15:32:20 +0530 Subject: [PATCH 1/3] bip327: minor fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - An error test vector doesn’t specify the InvalidContributionError type - In *DeterministicSign*, use GetXonlyPubkey instead of GetPubkey - The key_agg_and_tweak fn doesn’t specify the return type - In partial_sig_verify_internal, the pubkey arg should be PlainPk - Remove unused enumerate() fn calls - In test_sign_verify, add an additional assert statement --- bip-0327.mediawiki | 2 +- bip-0327/gen_vectors_helper.py | 3 ++- bip-0327/reference.py | 25 ++++++++++++++----------- bip-0327/vectors/sig_agg_vectors.json | 3 ++- 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/bip-0327.mediawiki b/bip-0327.mediawiki index b659629b..77a0024e 100644 --- a/bip-0327.mediawiki +++ b/bip-0327.mediawiki @@ -619,7 +619,7 @@ Algorithm ''DeterministicSign(sk, aggothernonce, pk1..u, tweak1. * Let ''keyagg_ctx0 = KeyAgg(pk1..u)''; fail if that fails * For ''i = 1 .. v'': ** Let ''keyagg_ctxi = ApplyTweak(keyagg_ctxi-1, tweaki, is_xonly_ti)''; fail if that fails -* Let ''aggpk = GetPubkey(keyagg_ctxv)'' +* Let ''aggpk = GetXonlyPubkey(keyagg_ctxv)'' * Let ''ki = int(hashMuSig/deterministic/nonce(sk' || aggothernonce || aggpk || bytes(8, len(m)) || m || bytes(1, i - 1))) mod n'' for ''i = 1,2'' * Fail if ''k1 = 0'' or ''k2 = 0'' * Let ''R⁎,1 = k1⋅G, R⁎,2 = k2⋅G'' diff --git a/bip-0327/gen_vectors_helper.py b/bip-0327/gen_vectors_helper.py index a70bb6f3..03c2dbb2 100644 --- a/bip-0327/gen_vectors_helper.py +++ b/bip-0327/gen_vectors_helper.py @@ -153,7 +153,8 @@ def sig_agg_vectors(): "psig_indices": [7, 8], "error": { "type": "invalid_contribution", - "signer": 1 + "signer": 1, + "contrib": "psig", }, "comment": "Partial signature is invalid because it exceeds group size" } diff --git a/bip-0327/reference.py b/bip-0327/reference.py index edf6e76b..cc1af505 100644 --- a/bip-0327/reference.py +++ b/bip-0327/reference.py @@ -317,7 +317,7 @@ SessionContext = NamedTuple('SessionContext', [('aggnonce', bytes), ('is_xonly', List[bool]), ('msg', bytes)]) -def key_agg_and_tweak(pubkeys: List[PlainPk], tweaks: List[bytes], is_xonly: List[bool]): +def key_agg_and_tweak(pubkeys: List[PlainPk], tweaks: List[bytes], is_xonly: List[bool]) -> KeyAggContext: if len(tweaks) != len(is_xonly): raise ValueError('The `tweaks` and `is_xonly` arrays must have the same length.') keyagg_ctx = key_agg(pubkeys) @@ -367,7 +367,7 @@ def sign(secnonce: bytearray, sk: bytes, session_ctx: SessionContext) -> bytes: raise ValueError('secret key value is out of range.') P = point_mul(G, d_) assert P is not None - pk = cbytes(P) + pk = PlainPk(cbytes(P)) if not pk == secnonce[64:97]: raise ValueError('Public key does not match nonce_gen argument') a = get_session_key_agg_coeff(session_ctx, P) @@ -430,7 +430,7 @@ def partial_sig_verify(psig: bytes, pubnonces: List[bytes], pubkeys: List[PlainP session_ctx = SessionContext(aggnonce, pubkeys, tweaks, is_xonly, msg) return partial_sig_verify_internal(psig, pubnonces[i], pubkeys[i], session_ctx) -def partial_sig_verify_internal(psig: bytes, pubnonce: bytes, pk: bytes, session_ctx: SessionContext) -> bool: +def partial_sig_verify_internal(psig: bytes, pubnonce: bytes, pk: PlainPk, session_ctx: SessionContext) -> bool: (Q, gacc, _, b, R, e) = get_session_values(session_ctx) s = int_from_bytes(psig) if s >= n: @@ -523,7 +523,7 @@ def test_key_agg_vectors() -> None: assert get_xonly_pk(key_agg(pubkeys)) == expected - for i, test_case in enumerate(error_test_cases): + for test_case in error_test_cases: exception, except_fn = get_error_details(test_case) pubkeys = [X[i] for i in test_case["key_indices"]] @@ -572,7 +572,7 @@ def test_nonce_agg_vectors() -> None: expected = bytes.fromhex(test_case["expected"]) assert nonce_agg(pubnonces) == expected - for i, test_case in enumerate(error_test_cases): + for test_case in error_test_cases: exception, except_fn = get_error_details(test_case) pubnonces = [pnonce[i] for i in test_case["pnonce_indices"]] assert_raises(exception, lambda: nonce_agg(pubnonces), except_fn) @@ -598,7 +598,10 @@ def test_sign_verify_vectors() -> None: aggnonces = fromhex_all(test_data["aggnonces"]) # The aggregate of the first three elements of pnonce is at index 0 - assert(aggnonces[0] == nonce_agg([pnonce[0], pnonce[1], pnonce[2]])) + assert (aggnonces[0] == nonce_agg([pnonce[0], pnonce[1], pnonce[2]])) + # The aggregate of the first and fourth elements of pnonce is at index 1, + # which is the infinity point encoded as a zeroed 33-byte array + assert (aggnonces[1] == nonce_agg([pnonce[0], pnonce[3]])) msgs = fromhex_all(test_data["msgs"]) @@ -626,7 +629,7 @@ def test_sign_verify_vectors() -> None: assert sign(secnonce_tmp, sk, session_ctx) == expected assert partial_sig_verify(expected, pubnonces, pubkeys, [], [], msg, signer_index) - for i, test_case in enumerate(sign_error_test_cases): + for test_case in sign_error_test_cases: exception, except_fn = get_error_details(test_case) pubkeys = [X[i] for i in test_case["key_indices"]] @@ -646,7 +649,7 @@ def test_sign_verify_vectors() -> None: assert not partial_sig_verify(sig, pubnonces, pubkeys, [], [], msg, signer_index) - for i, test_case in enumerate(verify_error_test_cases): + for test_case in verify_error_test_cases: exception, except_fn = get_error_details(test_case) sig = bytes.fromhex(test_case["sig"]) @@ -702,7 +705,7 @@ def test_tweak_vectors() -> None: assert sign(secnonce_tmp, sk, session_ctx) == expected assert partial_sig_verify(expected, pubnonces, pubkeys, tweaks, is_xonly, msg, signer_index) - for i, test_case in enumerate(error_test_cases): + for test_case in error_test_cases: exception, except_fn = get_error_details(test_case) pubkeys = [X[i] for i in test_case["key_indices"]] @@ -747,7 +750,7 @@ def test_det_sign_vectors() -> None: session_ctx = SessionContext(aggnonce, pubkeys, tweaks, is_xonly, msg) assert partial_sig_verify_internal(psig, pubnonce, pubkeys[signer_index], session_ctx) - for i, test_case in enumerate(error_test_cases): + for test_case in error_test_cases: exception, except_fn = get_error_details(test_case) pubkeys = [X[i] for i in test_case["key_indices"]] @@ -796,7 +799,7 @@ def test_sig_agg_vectors() -> None: aggpk = get_xonly_pk(key_agg_and_tweak(pubkeys, tweaks, is_xonly)) assert schnorr_verify(msg, aggpk, sig) - for i, test_case in enumerate(error_test_cases): + for test_case in error_test_cases: exception, except_fn = get_error_details(test_case) pubnonces = [pnonce[i] for i in test_case["nonce_indices"]] diff --git a/bip-0327/vectors/sig_agg_vectors.json b/bip-0327/vectors/sig_agg_vectors.json index 04a7bc6b..519562c3 100644 --- a/bip-0327/vectors/sig_agg_vectors.json +++ b/bip-0327/vectors/sig_agg_vectors.json @@ -143,7 +143,8 @@ ], "error": { "type": "invalid_contribution", - "signer": 1 + "signer": 1, + "contrib": "psig" }, "comment": "Partial signature is invalid because it exceeds group size" } From 0d79b5eeb56af44281618b12d3ee35ef0de932e0 Mon Sep 17 00:00:00 2001 From: siv2r Date: Thu, 18 Jul 2024 17:09:19 +0530 Subject: [PATCH 2/3] remove P = None check as cpoint never returns None --- bip-0327/reference.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/bip-0327/reference.py b/bip-0327/reference.py index cc1af505..dd3bf68c 100644 --- a/bip-0327/reference.py +++ b/bip-0327/reference.py @@ -440,8 +440,6 @@ def partial_sig_verify_internal(psig: bytes, pubnonce: bytes, pk: PlainPk, sessi Re_s_ = point_add(R_s1, point_mul(R_s2, b)) Re_s = Re_s_ if has_even_y(R) else point_negate(Re_s_) P = cpoint(pk) - if P is None: - return False a = get_session_key_agg_coeff(session_ctx, P) g = 1 if has_even_y(Q) else n - 1 g_ = g * gacc % n From 26bb1d8ea3e2f0f7e02e1ec37a4b70fbc0781f85 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Mon, 22 Jul 2024 14:14:33 +0000 Subject: [PATCH 3/3] bip-0327: 1.0.1 -> 1.0.2 (cherry picked from commit 4f2e6e7ffbd2fdc095ab8d59827be9da18b790be) --- bip-0327.mediawiki | 4 +++- bip-0327/reference.py | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/bip-0327.mediawiki b/bip-0327.mediawiki index 77a0024e..c9e88abd 100644 --- a/bip-0327.mediawiki +++ b/bip-0327.mediawiki @@ -782,6 +782,8 @@ An exception to this rule is MAJOR version zero (0.y.z) which is fo The MINOR version is incremented whenever the inputs or the output of an algorithm changes in a backward-compatible way or new backward-compatible functionality is added. The PATCH version is incremented for other changes that are noteworthy (bug fixes, test vectors, important clarifications, etc.). +* '''1.0.2''' (2024-07-22): +** Fix minor bug in the specification of ''DeterministicSign'' and add small improvement to a ''PartialSigAgg'' test vector. * '''1.0.1''' (2024-05-14): ** Fix minor issue in ''PartialSigVerify'' vectors. * '''1.0.0''' (2023-03-26): @@ -825,4 +827,4 @@ The PATCH version is incremented for other changes that are notewor == Acknowledgements == -We thank Brandon Black, Riccardo Casatta, Lloyd Fournier, Russell O'Connor, and Pieter Wuille for their contributions to this document. +We thank Brandon Black, Riccardo Casatta, Sivaram Dhakshinamoorthy, Lloyd Fournier, Russell O'Connor, and Pieter Wuille for their contributions to this document. diff --git a/bip-0327/reference.py b/bip-0327/reference.py index dd3bf68c..17831c5f 100644 --- a/bip-0327/reference.py +++ b/bip-0327/reference.py @@ -367,7 +367,7 @@ def sign(secnonce: bytearray, sk: bytes, session_ctx: SessionContext) -> bytes: raise ValueError('secret key value is out of range.') P = point_mul(G, d_) assert P is not None - pk = PlainPk(cbytes(P)) + pk = cbytes(P) if not pk == secnonce[64:97]: raise ValueError('Public key does not match nonce_gen argument') a = get_session_key_agg_coeff(session_ctx, P) @@ -430,7 +430,7 @@ def partial_sig_verify(psig: bytes, pubnonces: List[bytes], pubkeys: List[PlainP session_ctx = SessionContext(aggnonce, pubkeys, tweaks, is_xonly, msg) return partial_sig_verify_internal(psig, pubnonces[i], pubkeys[i], session_ctx) -def partial_sig_verify_internal(psig: bytes, pubnonce: bytes, pk: PlainPk, session_ctx: SessionContext) -> bool: +def partial_sig_verify_internal(psig: bytes, pubnonce: bytes, pk: bytes, session_ctx: SessionContext) -> bool: (Q, gacc, _, b, R, e) = get_session_values(session_ctx) s = int_from_bytes(psig) if s >= n: