You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
DLEQ follows BIP374 0.2: the challenge is not reduced mod n and e >= n is not refused #149
ecc.dleq follows BIP374 0.2, not 0.3.0. BIP374 0.3.0 (bitcoin/bips#2262) reduces the challenge e modulo n and makes verification reject a proof with e ≥ n. Ours keeps the hash unreduced and does not range-check e. Its comments say that is what BIP374 asks, which is no longer true.
Where
At btclib-ecc main (11f2741), src/btclib_ecc/ecc/dleq.py:
:81-102, _challenge: returns the tagged hash as an int, and its docstring says the challenge "is not reduced modulo n".
:172-174, generate_proof: writes that unreduced e into the proof.
:209-216, assert_proof_as_valid: reads e with no range check; the comment at :211-214 calls that asymmetry "BIP374's".
:225: compares e with the unreduced hash.
:238-243: the docstring lists what the reference answers False for, and the list lacks e >= GE.ORDER.
How it is known
Read at bitcoin/bips 927b6de9 (commit c88e295d bumps BIP374 to 0.3.0):
bip-0374.mediawiki:82, generation: e = int(hash(...)) mod n.
bip-0374.mediawiki:109, verification: fail if e ≠ int(hash(...)) mod n.
bip-0374.mediawiki:128, changelog: "reject proofs with e ≥ n".
bip-0374/reference.py:39 returns dleq_challenge(...) % GE.ORDER, and :79 returns False for e >= GE.ORDER.
Ours was read from the source and not run against the 0.3.0 vectors.
Why it matters
The two differ only when the hash is at least n, about one hash in 2^128. Then ours writes a proof that a 0.3.0 verifier rejects, and rejects the proof a 0.3.0 prover writes. btclib-wallet imports this module for BIP375 silent-payment DLEQ proofs (src/btclib_wallet/psbt/silent_payments.py:105 at btclib-wallet abfcc6d).
Fix
Reduce the challenge modulo n in _challenge. In verification, refuse e ≥ n before any point arithmetic, next to the s ≥ n check. Rewrite the comments at :84-89, :211-214 and :238-243 to cite BIP374 0.3.0.
The vendored BIP374 vectors, including commit fc874dd5's new out-of-range cases, are ISS 146's scope, not this issue's.
Done when
verify_proof answers False for a proof whose first 32 bytes encode an e ≥ n.
generate_proof writes e mod n.
No comment in dleq.py says BIP374 leaves e unreduced.
Made with my usual tools: a computer, the Internet and an LLM. The mistakes, as usual, are all mine.
Correction to the body: the BIP374 0.3.0 vectors are already vendored (pinned at fc874dd5 in tests/_data/README.md), and test_verify_proof_vectors runs their e = n and s = n cases. They are not ISS 146's scope. PR 153 changes the code only.
Activity
fametrano commentedon Oct 6, 2026
A session is taking this issue.
DLEQ follows BIP374 0.3.0: reduce the challenge, refuse e >= n
DLEQ follows BIP374 0.3.0: reduce the challenge, refuse e >= n (closes …
fametrano commentedon Oct 6, 2026
Correction to the body: the BIP374 0.3.0 vectors are already vendored (pinned at fc874dd5 in
tests/_data/README.md), andtest_verify_proof_vectorsruns their e = n and s = n cases. They are not ISS 146's scope. PR 153 changes the code only.DLEQ follows BIP374 0.3.0: reduce the challenge, refuse e >= n (closes …
DLEQ follows BIP374 0.3.0: reduce the challenge, refuse e >= n (closes …