Skip to content

Commit 200f9b2

Browse files
real-or-randomsipa
authored andcommitted
bip340: Allow variable-length messages
1 parent 6163d36 commit 200f9b2

File tree

4 files changed

+51
-8
lines changed

4 files changed

+51
-8
lines changed

bip-0340.mediawiki

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ As an alternative to generating keys randomly, it is also possible and safe to r
138138

139139
Input:
140140
* The secret key ''sk'': a 32-byte array
141-
* The message ''m'': a 32-byte array
141+
* The message ''m'': a byte array
142142
* Auxiliary random data ''a'': a 32-byte array
143143
144144
The algorithm ''Sign(sk, m)'' is defined as:
@@ -174,7 +174,7 @@ It should be noted that various alternative signing algorithms can be used to pr
174174

175175
Input:
176176
* The public key ''pk'': a 32-byte array
177-
* The message ''m'': a 32-byte array
177+
* The message ''m'': a byte array
178178
* A signature ''sig'': a 64-byte array
179179
180180
The algorithm ''Verify(pk, m, sig)'' is defined as:
@@ -197,7 +197,7 @@ Note that the correctness of verification relies on the fact that ''lift_x'' alw
197197
Input:
198198
* The number ''u'' of signatures
199199
* The public keys ''pk<sub>1..u</sub>'': ''u'' 32-byte arrays
200-
* The messages ''m<sub>1..u</sub>'': ''u'' 32-byte arrays
200+
* The messages ''m<sub>1..u</sub>'': ''u'' byte arrays
201201
* The signatures ''sig<sub>1..u</sub>'': ''u'' 64-byte arrays
202202
203203
The algorithm ''BatchVerify(pk<sub>1..u</sub>, m<sub>1..u</sub>, sig<sub>1..u</sub>)'' is defined as:
@@ -213,6 +213,30 @@ The algorithm ''BatchVerify(pk<sub>1..u</sub>, m<sub>1..u</sub>, sig<sub>1..u</s
213213
214214
If all individual signatures are valid (i.e., ''Verify'' would return success for them), ''BatchVerify'' will always return success. If at least one signature is invalid, ''BatchVerify'' will return success with at most a negligible probability.
215215

216+
=== Usage Considerations ===
217+
218+
==== Messages of Arbitrary Size ====
219+
220+
The signature scheme specified in this BIP accepts byte strings of arbitrary size as input messages.<ref>In theory, the message size is restricted due to the fact that SHA256 accepts byte strings only up to size of 2^61-1 bytes.</ref>
221+
It is understood that implementations may reject messages which are too large in their environment or application context,
222+
e.g., messages which exceed predefined buffers or would otherwise cause resource exhaustion.
223+
224+
Earlier revisions of this BIP required messages to be exactly 32 bytes.
225+
This restriction puts a burden on callers
226+
who typically need to perform pre-hashing of the actual input message by feeding it through SHA256 (or another collision-resistant cryptographic hash function)
227+
to create a 32-byte digest which can be passed to signing or verification
228+
(as for example done in [[bip-0341.mediawiki|BIP341]].)
229+
230+
Since pre-hashing may not always be desirable,
231+
e.g., when actual messages are shorter than 32 bytes,<ref>Another reason to omit pre-hashing is to protect against certain types of cryptanalytic advances against the hash function used for pre-hashing: If pre-hashing is used, an attacker that can find collisions in the pre-hashing function can necessarily forge signatures under chosen-message attacks. If pre-hashing is not used, an attacker that can find collisions in SHA256 (as used inside the signature scheme) may not be able to forge signatures. However, this seeming advantage is mostly irrelevant in the context of Bitcoin, which already relies on collision resistance of SHA256 in other places, e.g., for transaction hashes.</ref>
232+
the restriction to 32-byte messages has been lifted.
233+
We note that pre-hashing is recommended for performance reasons in applications that deal with large messages.
234+
If large messages are not pre-hashed,
235+
the algorithms of the signature scheme will perform more hashing internally.
236+
In particular, the signing algorithm needs two sequential hashing passes over the message,
237+
which means that the full message must necessarily be kept in memory during signing,
238+
and large messages entail a runtime penalty.<ref>Typically, messages of 56 bytes or longer enjoy a performance benefit from pre-hashing, assuming the speed of SHA256 inside the signing algorithm matches that of the pre-hashing done by the calling application.</ref>
239+
216240
== Applications ==
217241

218242
There are several interesting applications beyond simple signatures.
@@ -248,6 +272,7 @@ The reference implementation is for demonstration purposes only and not to be us
248272
To help implementors understand updates to this BIP, we keep a list of substantial changes.
249273

250274
* 2022-08: Fix function signature of lift_x in reference code
275+
* 2023-04: Allow messages of arbitrary size
251276
252277
== Footnotes ==
253278

bip-0340/reference.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,6 @@ def pubkey_gen(seckey: bytes) -> bytes:
9696
return bytes_from_point(P)
9797

9898
def schnorr_sign(msg: bytes, seckey: bytes, aux_rand: bytes) -> bytes:
99-
if len(msg) != 32:
100-
raise ValueError('The message must be a 32-byte array.')
10199
d0 = int_from_bytes(seckey)
102100
if not (1 <= d0 <= n - 1):
103101
raise ValueError('The secret key must be an integer in the range 1..n-1.')
@@ -121,8 +119,6 @@ def schnorr_sign(msg: bytes, seckey: bytes, aux_rand: bytes) -> bytes:
121119
return sig
122120

123121
def schnorr_verify(msg: bytes, pubkey: bytes, sig: bytes) -> bool:
124-
if len(msg) != 32:
125-
raise ValueError('The message must be a 32-byte array.')
126122
if len(pubkey) != 32:
127123
raise ValueError('The public key must be a 32-byte array.')
128124
if len(sig) != 64:

bip-0340/test-vectors.csv

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,7 @@ index,secret key,public key,aux_rand,message,signature,verification result,comme
1414
12,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F69E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B,FALSE,sig[0:32] is equal to field size
1515
13,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E177769FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141,FALSE,sig[32:64] is equal to curve order
1616
14,,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30,,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E17776969E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B,FALSE,public key is not a valid X coordinate because it exceeds the field size
17+
15,0340034003400340034003400340034003400340034003400340034003400340,778CAA53B4393AC467774D09497A87224BF9FAB6F6E68B23086497324D6FD117,0000000000000000000000000000000000000000000000000000000000000000,,71535DB165ECD9FBBC046E5FFAEA61186BB6AD436732FCCC25291A55895464CF6069CE26BF03466228F19A3A62DB8A649F2D560FAC652827D1AF0574E427AB63,TRUE,message of size 0 (added 2022-12)
18+
16,0340034003400340034003400340034003400340034003400340034003400340,778CAA53B4393AC467774D09497A87224BF9FAB6F6E68B23086497324D6FD117,0000000000000000000000000000000000000000000000000000000000000000,11,08A20A0AFEF64124649232E0693C583AB1B9934AE63B4C3511F3AE1134C6A303EA3173BFEA6683BD101FA5AA5DBC1996FE7CACFC5A577D33EC14564CEC2BACBF,TRUE,message of size 1 (added 2022-12)
19+
17,0340034003400340034003400340034003400340034003400340034003400340,778CAA53B4393AC467774D09497A87224BF9FAB6F6E68B23086497324D6FD117,0000000000000000000000000000000000000000000000000000000000000000,0102030405060708090A0B0C0D0E0F1011,5130F39A4059B43BC7CAC09A19ECE52B5D8699D1A71E3C52DA9AFDB6B50AC370C4A482B77BF960F8681540E25B6771ECE1E5A37FD80E5A51897C5566A97EA5A5,TRUE,message of size 17 (added 2022-12)
20+
18,0340034003400340034003400340034003400340034003400340034003400340,778CAA53B4393AC467774D09497A87224BF9FAB6F6E68B23086497324D6FD117,0000000000000000000000000000000000000000000000000000000000000000,99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999,403B12B0D8555A344175EA7EC746566303321E5DBFA8BE6F091635163ECA79A8585ED3E3170807E7C03B720FC54C7B23897FCBA0E9D0B4A06894CFD249F22367,TRUE,message of size 100 (added 2022-12)

bip-0340/test-vectors.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,20 @@ def vector14():
249249

250250
return (None, pubkey, None, msg, sig, "FALSE", "public key is not a valid X coordinate because it exceeds the field size")
251251

252+
def varlen_vector(msg_int):
253+
seckey = bytes_from_int(int(16 * "0340", 16))
254+
pubkey = pubkey_gen(seckey)
255+
aux_rand = bytes_from_int(0)
256+
msg = msg_int.to_bytes((msg_int.bit_length() + 7) // 8, "big")
257+
sig = schnorr_sign(msg, seckey, aux_rand)
258+
comment = "message of size %d (added 2022-12)"
259+
return (seckey, pubkey, aux_rand, msg, sig, "TRUE", comment % len(msg))
260+
261+
vector15 = lambda : varlen_vector(0)
262+
vector16 = lambda : varlen_vector(0x11)
263+
vector17 = lambda : varlen_vector(0x0102030405060708090A0B0C0D0E0F1011)
264+
vector18 = lambda : varlen_vector(int(100 * "99", 16))
265+
252266
vectors = [
253267
vector0(),
254268
vector1(),
@@ -264,7 +278,11 @@ def vector14():
264278
vector11(),
265279
vector12(),
266280
vector13(),
267-
vector14()
281+
vector14(),
282+
vector15(),
283+
vector16(),
284+
vector17(),
285+
vector18(),
268286
]
269287

270288
# Converts the byte strings of a test vector into hex strings

0 commit comments

Comments
 (0)