Skip to content

keys: schnorr_sign and schnorr_verify take a message of any length - #20

Open
fametrano wants to merge 1 commit into
spesmilo:masterfrom
fametrano:schnorr-any-message-length
Open

keys: schnorr_sign and schnorr_verify take a message of any length#20
fametrano wants to merge 1 commit into
spesmilo:masterfrom
fametrano:schnorr-any-message-length

Conversation

@fametrano

Copy link
Copy Markdown
Contributor

BIP-340 signs a message of any length, and secp256k1_schnorrsig_verify already takes msglen, but schnorr_verify passes a hard-coded 32 and schnorr_sign is bound to secp256k1_schnorrsig_sign32. Both guard the length with assert, which python -O removes. On 0.0.7 under -O:

schnorr_sign(31 bytes) == schnorr_sign(32 zero bytes)   -> True   (the buffer is read past its end)
schnorr_verify(sig over 32 zero bytes, 31-byte message) -> True

Changes:

  • bind secp256k1_schnorrsig_sign_custom and call it with the BIP-340 nonce function and the aux bytes in extraparams, passing the real message length; schnorr_verify passes len(msg);
  • raise TypeError/ValueError on a wrong type or length instead of asserting;
  • add BIP-340 vectors 15 to 18 (messages of size 0, 1, 17 and 100) and a test for the rejected inputs.

The first parameter is renamed from msg32 to msg; every caller in spesmilo/electrum and spesmilo/notary passes it positionally. The ECDSA methods keep msg32, since they take a digest.

pytest tests: 11 passed, 19 subtests. The new vectors and the new test fail on master.

BIP-340 signs a message of any length, and libsecp256k1's
secp256k1_schnorrsig_verify already takes msglen, but schnorr_verify
passed a hard-coded 32 and schnorr_sign was bound to
secp256k1_schnorrsig_sign32. Bind secp256k1_schnorrsig_sign_custom
with the BIP-340 nonce function and the aux bytes in its extraparams,
and pass the real length on both sides.

The length guards were asserts, which python -O removes: a 31-byte
message was then signed and verified as if it were the first 32 bytes
of the buffer. Raise ValueError and TypeError instead.

Add BIP-340 vectors 15 to 18, the messages of size 0, 1, 17 and 100.
@SomberNight

Copy link
Copy Markdown
Member

This PR is doing several things.

Both guard the length with assert, which python -O removes. On 0.0.7 under -O

This would be fixed by #18
(which Electrum itself is already doing so usage of the library from there is unaffected)

Do you have a use case for signing arbitrary length messages (secp256k1_schnorrsig_sign_custom)?

@fametrano

Copy link
Copy Markdown
Contributor Author

Thanks — you're right that #18 covers the -O case; with asserts refused-off at import, the out-of-bounds read is no longer reachable on master, so that part of the motivation is moot.

On arbitrary length: BIP-340 signs messages of any size (the 2023-04 "Messages of Arbitrary Size" amendment), and schnorrsig_sign_custom is the API for it, so the "use case" is really the standard's rather than a caller's to justify. For electrum-ecc the narrower question is yours: should the Schnorr API accept a message other than 32 bytes at all? Every current caller in Electrum and notary passes a 32-byte digest, so nothing here needs it today.

Two clean options:

  1. 32-byte only. Stay on sign32, but turn the length check into an explicit raise (asserts are enabled via ensure asserts are enabled: dupe check from electrum #18, but the library's own note says code shouldn't rely on that) and document the message as a 32-byte digest by design. Independently of the choice, verify currently hardcodes msglen=32 and silently ignores bytes past the first 32 rather than rejecting them — that's the one part worth fixing either way.

  2. Any length. Bind schnorrsig_sign_custom and pass the real length through, making the library a faithful BIP-340 signer.

I'm happy to reduce this PR to option 1 if that's your preference — just say which way you'd like to take it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants