Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions bip-0374.mediawiki
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
License: BSD-2-Clause
Discussion: https://gist.github.com/andrewtoth/df97c3260cc8d12f09d3855ee61322ea
https://groups.google.com/g/bitcoindev/c/MezoKV5md7s
Version: 0.2.0
Version: 0.3.0
</pre>

== Introduction ==
Expand Down Expand Up @@ -79,7 +79,7 @@ The algorithm ''GenerateProof(a, B, r, G, m)'' is defined as:
* Fail if ''k = 0''.
* Let ''R<sub>1</sub> = k⋅G''.
* Let ''R<sub>2</sub> = k⋅B''.
* Let ''e = int(hash<sub>BIP0374/challenge</sub>(cbytes(A) || cbytes(B) || cbytes(C) || cbytes(G) || cbytes(R<sub>1</sub>) || cbytes(R<sub>2</sub>) || m'))''.
* Let ''e = int(hash<sub>BIP0374/challenge</sub>(cbytes(A) || cbytes(B) || cbytes(C) || cbytes(G) || cbytes(R<sub>1</sub>) || cbytes(R<sub>2</sub>) || m')) mod n''.
* Let ''s = (k + e⋅a) mod n''.
* Let ''proof = bytes(32, e) || bytes(32, s)''.
* If ''VerifyProof(A, B, C, proof, G, m)'' (see below) returns failure, abort.
Expand All @@ -99,14 +99,14 @@ Input:

The algorithm ''VerifyProof(A, B, C, proof, G, m)'' is defined as:
* Fail if any of ''is_infinite(A)'', ''is_infinite(B)'', ''is_infinite(C)'', ''is_infinite(G)''
* Let ''e = int(proof[0:32])''.
* Let ''e = int(proof[0:32])''; fail if ''e &ge; n''.
* Let ''s = int(proof[32:64])''; fail if ''s &ge; n''.
* Let ''R<sub>1</sub> = s⋅G - e⋅A''.
* Fail if ''is_infinite(R<sub>1</sub>)''.
* Let ''R<sub>2</sub> = s⋅B - e⋅C''.
* Fail if ''is_infinite(R<sub>2</sub>)''.
* Let ''m' = m if m is provided, otherwise an empty byte array''.
* Fail if ''e ≠ int(hash<sub>BIP0374/challenge</sub>(cbytes(A) || cbytes(B) || cbytes(C) || cbytes(G) || cbytes(R<sub>1</sub>) || cbytes(R<sub>2</sub>) || m'))''.
* Fail if ''e ≠ int(hash<sub>BIP0374/challenge</sub>(cbytes(A) || cbytes(B) || cbytes(C) || cbytes(G) || cbytes(R<sub>1</sub>) || cbytes(R<sub>2</sub>) || m')) mod n''.
* Return success iff no failure occurred before reaching this point.

==Backwards Compatibility==
Expand All @@ -124,6 +124,8 @@ Test vectors can be generated by running <code>./bip-0374/gen_test_vectors.py</c

== Changelog ==

* 0.3.0 (2026-08-19):
** Treat the challenge ''e'' as a scalar (reduced modulo the curve order) and reject proofs with ''e &ge; n''
* 0.2.0 (2025-02-27):
** Add the message to the rand computation
* 0.1.0 (2024-12-26):
Expand Down
13 changes: 13 additions & 0 deletions bip-0374/gen_test_vectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,19 @@ def gen_all_verify_proof_vectors(f):
C.to_bytes_compressed().hex(), proof.hex(), msg_damaged.hex(), "FALSE", f"Tampered message (random bit-flip)"))
idx += 1

# out-of-range proof values should fail (e and s must both be valid scalars)
order_bytes = GE.ORDER.to_bytes(32, "big")
proof_e_out_of_range = order_bytes + proof[32:]
assert not dleq_verify_proof(A, B, C, proof_e_out_of_range, G=G, m=msg)
writer.writerow((idx, G.to_bytes_compressed().hex(), A.to_bytes_compressed().hex(), B.to_bytes_compressed().hex(),
C.to_bytes_compressed().hex(), proof_e_out_of_range.hex(), msg.hex(), "FALSE", f"Proof with e equal to curve order"))
idx += 1
proof_s_out_of_range = proof[:32] + order_bytes
assert not dleq_verify_proof(A, B, C, proof_s_out_of_range, G=G, m=msg)
writer.writerow((idx, G.to_bytes_compressed().hex(), A.to_bytes_compressed().hex(), B.to_bytes_compressed().hex(),
C.to_bytes_compressed().hex(), proof_s_out_of_range.hex(), msg.hex(), "FALSE", f"Proof with s equal to curve order"))
idx += 1


if __name__ == "__main__":
print(f"Generating {FILENAME_GENERATE_PROOF_TEST}...")
Expand Down
4 changes: 3 additions & 1 deletion bip-0374/reference.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def dleq_challenge(
+ m,
),
"big",
)
) % GE.ORDER

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

leaving a note for reviewers that we could also take better use of secp256k1lab's types in the reference implementation (e.g. directly return a Scalar here instead of working with ints), but that's out of scope for this PR



def dleq_generate_proof(
Expand Down Expand Up @@ -76,6 +76,8 @@ def dleq_verify_proof(
return False
assert len(proof) == 64
e = int.from_bytes(proof[:32], "big")
if e >= GE.ORDER:
return False
s = int.from_bytes(proof[32:], "big")
if s >= GE.ORDER:
return False
Expand Down
2 changes: 2 additions & 0 deletions bip-0374/test_vectors_verify_proof.csv
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@ index,point_G,point_A,point_B,point_C,proof,message,result_success,comment
12,0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,03d9a98624c0c74fc7eebd39ed84175f80d03c774908e75ca737a0745d1c64e20a,021cb81121a00f89769903305a367ad3cc02d5b402b12c026e06ac94bde28cd608,03611410561c35dae13135e4ad8094baac9bbcf2f4e18498181a8ff8a6d43be9d9,78a5544afa75bf152653fe55fb76926f2f65131bf090972a0b0b37d310c28a6bde0e7bfacc10ac12d36f55316ba134b6ba0b844a65ae05cad53c0b296c6639bb,22616bb5fb2d7c68270f305122f2a09e833239c4b1c9a04e285119fb606ac794,FALSE,Swapped points case 5
13,0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,03611410561c35dae13135e4ad8094baac9bbcf2f4e18498181a8ff8a6d43be9d9,021cb81121a00f89769903305a367ad3cc02d5b402b12c026e06ac94bde28cd608,03d9a98624c0c74fc7eebd39ed84175f80d03c774908e75ca737a0745d1c64e20a,78a5544afa75bf152653fe55fb76926f2f65131ff090972a0b0b37d310c28a6bde0e7bfacc10ac12d36f55316ba134b6ba0b844a65ae05cad53c0b296c6639bb,22616bb5fb2d7c68270f305122f2a09e833239c4b1c9a04e285119fb606ac794,FALSE,Tampered proof (random bit-flip)
14,0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,03611410561c35dae13135e4ad8094baac9bbcf2f4e18498181a8ff8a6d43be9d9,021cb81121a00f89769903305a367ad3cc02d5b402b12c026e06ac94bde28cd608,03d9a98624c0c74fc7eebd39ed84175f80d03c774908e75ca737a0745d1c64e20a,78a5544afa75bf152653fe55fb76926f2f65131bf090972a0b0b37d310c28a6bde0e7bfacc10ac12d36f55316ba134b6ba0b844a65ae05cad53c0b296c6639bb,22616bb5fb6d7c68270f305122f2a09e833239c4b1c9a04e285119fb606ac794,FALSE,Tampered message (random bit-flip)
15,0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,03611410561c35dae13135e4ad8094baac9bbcf2f4e18498181a8ff8a6d43be9d9,021cb81121a00f89769903305a367ad3cc02d5b402b12c026e06ac94bde28cd608,03d9a98624c0c74fc7eebd39ed84175f80d03c774908e75ca737a0745d1c64e20a,fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141de0e7bfacc10ac12d36f55316ba134b6ba0b844a65ae05cad53c0b296c6639bb,22616bb5fb2d7c68270f305122f2a09e833239c4b1c9a04e285119fb606ac794,FALSE,Proof with e equal to curve order
16,0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,03611410561c35dae13135e4ad8094baac9bbcf2f4e18498181a8ff8a6d43be9d9,021cb81121a00f89769903305a367ad3cc02d5b402b12c026e06ac94bde28cd608,03d9a98624c0c74fc7eebd39ed84175f80d03c774908e75ca737a0745d1c64e20a,78a5544afa75bf152653fe55fb76926f2f65131bf090972a0b0b37d310c28a6bfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141,22616bb5fb2d7c68270f305122f2a09e833239c4b1c9a04e285119fb606ac794,FALSE,Proof with s equal to curve order