Skip to content

DLEQ follows BIP374 0.2: the challenge is not reduced mod n and e >= n is not refused #149

Closed

Description

@fametrano

What is wrong

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.

Activity

  1. fametrano commented on Oct 6, 2026

    @fametrano
    MemberAuthor

    A session is taking this issue.

  2. added 2 commits that reference this issue on Oct 6, 2026
    a10db0d
    7a11cbf
  3. fametrano commented on Oct 6, 2026

    @fametrano
    MemberAuthor

    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.

  4. added 2 commits that reference this issue on Oct 7, 2026
    3bf8c0a
    9ac8928
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions