bip-0327: add more test vectors #2351

pull jonasnick wants to merge 7 commits into bitcoin:master from jonasnick:bip-0327-test-vectors changing 9 files +264 −12
  1. jonasnick commented at 4:10 PM on November 10, 2026: contributor

    No description provided.

  2. jonasnick marked this as a draft on Nov 10, 2026
  3. jonasnick commented at 4:18 PM on November 10, 2026: contributor

    Ideally, we try those test vectors in an implementation (libsecp? btclib-ecc? ...) before a merge.

  4. jonatack added the label BIP Update by Owner on Nov 10, 2026
  5. jonatack added the label Tests on Nov 10, 2026
  6. fametrano commented at 10:58 PM on November 10, 2026: contributor

    tACK 2061baf3

    You asked for these vectors to be tried in an implementation, and #2329 came from btclib-org/ecc's tests, so I ran them there. ecc passes every case of the six changed files: 359 passed, 4 skipped, the same four tests that skip with the 1.0.4 vectors, and every case runs in ecc's own vector tests. The reference implementation's tests pass too. I also made each mistake a rationale names in reference.py, one at a time: each such copy passes the 1.0.4 vectors and fails these, with one exception.

    The exception is the 4-byte extra_in case, whose rationale should read "Detects implementations that encode the length of extra_in as 32 whenever extra_in is present". The constant 32 it names now is already caught by the NonceGen vector with every optional argument absent.

    Details: https://gist.github.com/fametrano/b4bd8510da2f247f27d324b2d7e25623/7e4ef292a5e559b8b74d7f2cf66afa799c6d7398

  7. in bip-0327.mediawiki:530 in 2061baf331
     526 | @@ -527,6 +527,9 @@ We provide a naive, highly inefficient, and non-constant time [[bip-0327/referen
     527 |  
     528 |  Standalone JSON test vectors are also available in the [[bip-0327|same directory]], to facilitate porting the test vectors into other implementations.
     529 |  
     530 | +Each test vector should detect a plausible implementation mistake that no other test vector detects.
    


    real-or-random commented at 2:51 PM on November 12, 2026:

    I suggest dropping this requirement. The existing test vectors probably do not meet it, and three of the new ones do not either: the 4-byte extra_in vector (see fametrano's review) and two Sign error vectors (see my other comments). Checking it requires comparing each vector against all others, which makes it hard to maintain whenever a vector is added. A rationale that names a mistake the vector detects is useful without it.


    jonasnick commented at 11:10 AM on November 13, 2026:

    I'd like to keep a clear decision rule for which vectors to add. Without such a rule, we could have kept the 100 byte message test vector in Ferdinando's original commit. I think the new test vectors do meet the criterion, but the stated rationale was wrong.

    Yes, no one checked the existing vectors, so we can make this rule only apply to new vectors. However, I think the BIP text is the wrong place for that. So I added a README.md to the vectors/ dir.

  8. in bip-0327.mediawiki:790 in 2061baf331
     784 | @@ -782,6 +785,9 @@ An exception to this rule is <code>MAJOR</code> version zero (0.y.z) which is fo
     785 |  The <code>MINOR</code> 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.
     786 |  The <code>PATCH</code> version is incremented for other changes that are noteworthy (bug fixes, test vectors, important clarifications, etc.).
     787 |  
     788 | +* '''1.0.5''' (2026-11-10):
     789 | +** Add test vectors that detect implementation mistakes the previous test vectors missed, and improve a ''PartialSigVerify'' test vector.
     790 | +** Describe the purpose and scope of the test vectors, and state in a new <code>rationale</code> field which mistake each new test vector detects.
    


    real-or-random commented at 2:51 PM on November 12, 2026:

    If the uniqueness requirement is dropped (see the comment on the description of the test vectors):

    ** Describe the scope of the test vectors, and state in a new <code>rationale</code> field which mistake each new test vector detects.
    
  9. in bip-0327/vectors/sign_verify_vectors.json:185 in 2061baf331
     180 | +            "error": {
     181 | +                "type": "value",
     182 | +                "message": "second secnonce value is out of range."
     183 | +            },
     184 | +            "comment": "Secnonce is invalid because its second half is zero",
     185 | +            "rationale": "Detects implementations that check only the first secnonce value"
    


    real-or-random commented at 2:51 PM on November 12, 2026:

    The vectors with k2' = n and k2' > n also detect this mistake: an implementation that checks only k1' signs both without an error. The mistake that only this vector detects is a missing check that k2' is nonzero. If the requirement that each test vector detect a mistake that no other test vector detects stays, the rationale should name that one.

                "rationale": "Detects implementations that check only that k2' < n"
    

    jonasnick commented at 11:08 AM on November 13, 2026:

    Fixed

  10. in bip-0327/vectors/sign_verify_vectors.json:197 in 2061baf331
     192 | +            "error": {
     193 | +                "type": "value",
     194 | +                "message": "Public key does not match nonce_gen argument"
     195 | +            },
     196 | +            "comment": "Secnonce was generated for another signer's public key",
     197 | +            "rationale": "Detects implementations that do not compare secnonce[64:97] with the signer's public key"
    


    real-or-random commented at 2:51 PM on November 12, 2026:

    The vector with the negated public key below also detects this mistake. The mistakes that only this vector detects are using secnonce[64:97] as the signer's public key, and checking only that secnonce[64:97] is one of the public keys: this secnonce's public key belongs to the second signer, while the negated key in the other vector belongs to no signer. If the requirement that each test vector detect a mistake that no other test vector detects stays, the rationale should name those.

                "rationale": "Detects implementations that check only that secnonce[64:97] is one of the public keys, or that use secnonce[64:97] instead of the public key of sk"
    

    jonasnick commented at 11:08 AM on November 13, 2026:

    Fixed

  11. real-or-random commented at 2:54 PM on November 12, 2026: contributor

    Concept ACK 2061baf3313a69f35eebca714389f03dc817fd07

    I ran reference.py and gen_vectors_helper.py at this commit: the tests pass, and the generated sig_agg vectors match the JSON.

    I also applied the mistakes that the rationales of the new Sign error vectors name to reference.py, one at a time, and recorded which vectors detect each mistake. Every new vector detects the mistake its rationale names, but two rationales name a mistake that another new vector also detects (see inline), as does the rationale of the 4-byte extra_in vector that fametrano pointed out. I think this is fine for test vectors, but it contradicts the new requirement that each test vector detect a mistake that no other test vector detects, so I suggest dropping that requirement (see inline).

    (Reviewed with the help of Claude Opus 5.5)

  12. bip-0327: add test vectors and describe their scope
    Add Sign test vectors for a secnonce with k2' = 0 and for a secnonce
    generated for a different public key. No previous test vector detected
    an implementation that checks only k1', or one that omits the public
    key check added in 1.0.0-rc.2.
    
    Add test vectors for a single signer, a 4-byte extra_in, and plain and
    x-only tweaks in DeterministicSign. They detect implementations that
    reject a single signer, encode the length of extra_in as 32 whenever
    extra_in is present, or treat every tweak in DeterministicSign as
    x-only.
    
    State in the BIP that all inputs in the test vectors have the lengths
    that the algorithms require.
    
    Add a README to the vectors directory that states when to add a test
    vector: only if it detects a plausible implementation mistake that the
    other test vectors do not detect. Name that mistake in the comment of
    each added test vector.
    
    Co-authored-by: Ferdinando Ametrano <ferdinando@ametrano.net>
    1329c82269
  13. bip-0327: add test vectors for k2' >= n and 256-byte messages
    Add Sign test vectors with k2' = n and k2' = n + 1. Together they
    detect implementations that check the secret nonce values only for
    zero, that check k2' <= n instead of k2' < n, or that reduce k2' mod n
    before checking it for zero. No single value detects the last two:
    among values of at least n, checking k2' <= n accepts only n, while
    reducing first rejects only n. For k2' = n, the optional correctness
    check at the end of Sign also fails, because k2'*G is infinity, so this
    vector detects the k2' <= n mistake only in implementations that omit
    that check.
    
    Add NonceGen and DeterministicSign test vectors with a 256-byte
    message. They detect implementations that encode only the low byte of
    len(m); the longest message in the previous test vectors has 38 bytes.
    DeterministicSign needs its own vector because it encodes len(m)
    separately.
    314aeb92d5
  14. bip-0327: add test vectors for a public key and its negation
    A public key and its negation have the same X coordinate, and their
    compressed encodings differ only in the first byte. Add a Sign test
    vector with a secnonce generated for the negation of the signer's public
    key, and a KeyAgg test vector with a public key and its negation. They
    detect implementations that compare public keys only by their X
    coordinates, in the public key check of Sign, in GetSecondKey, or in
    KeyAggCoeffInternal. Distinct public keys in the previous test vectors
    also have distinct X coordinates.
    
    The public key check in Sign ensures that the secret key provided to
    Sign is determined when NonceGen is invoked. Comparing only X
    coordinates determines the secret key only up to negation.
    268f000387
  15. bip-0327: add a NonceGen test vector without repeated bytes
    In the previous NonceGen test vectors, every rand_ consists of the byte
    0F repeated 32 times, every present sk of the byte 02 repeated 32 times,
    and every pk has an even Y coordinate. Add a test vector whose rand_ and
    sk are not a repeated byte and whose pk has an odd Y coordinate. It
    detects implementations that reverse the byte order of rand_ or sk, that
    replace the first byte of pk with 02, or that use only the first byte of
    rand_.
    
    With the last mistake, two NonceGen invocations with the same other
    arguments return the same secnonce with probability 1/256, although the
    BIP requires that Sign is never executed twice with the same secnonce.
    5dee9150ee
  16. bip-0327: isolate the range check in a PartialSigVerify test vector
    The PartialSigVerify test vector with the partial signature n fails the
    verification equation even without the range check. So it does not
    detect implementations that omit the range check or that check s > n
    instead of s >= n. Change the pubnonces of the test vector such that the
    partial signature 0 is valid, keeping the aggregate nonce. Since
    n*G = 0*G, the partial signature n then satisfies the verification
    equation, and only the range check rejects it. The previous version of
    the test vector detects no mistake that the new version does not detect,
    so it is replaced rather than kept.
    
    gen_vectors_helper.py computes the new pubnonces.
    b56ca57a5b
  17. bip-0327: add test vectors for the signs of accumulated tweaks
    ApplyTweak multiplies gacc by g, which is -1 if an x-only tweak negates
    the aggregate public key. In every previous tweak sequence, the product
    of all values of g equals the last one. Add a test vector with two
    x-only tweaks, of which only the first negates the aggregate public key.
    It detects implementations that set gacc to g instead of multiplying it
    by g.
    
    PartialSigAgg adds e*g*tacc, where g is -1 if the aggregate public key Q
    has an odd Y coordinate. In the previous PartialSigAgg test vectors,
    tacc is 0 whenever Q has an odd Y coordinate. Add a test vector with a
    plain tweak and an odd Q, generated by gen_vectors_helper.py. It detects
    implementations that omit g.
    2514fce2df
  18. bip-0327: bump version to 1.0.5
    Add a changelog entry for the changes to the test vectors.
    43613a9792
  19. jonasnick force-pushed on Nov 13, 2026
  20. jonasnick commented at 11:09 AM on November 13, 2026: contributor

    Pushed a new version that addresses Tim's comments, removes the addition of the rationale field and instead places the rationale in the comment. @fametrano

    Thanks for testing the new vectors!

    The exception is the 4-byte extra_in case

    Right. I changed it to your suggestion.


github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bips. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-11-14 09:10 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me