1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
#![cfg_attr(feature = "std", doc = "```")]
#![cfg_attr(not(feature = "std"), doc = "```ignore")]
#![allow(non_snake_case, clippy::many_single_char_names)]
mod sign;
mod verify;
pub use self::{sign::SigningKey, verify::VerifyingKey};
pub use ecdsa_core::signature::{self, Error};
use crate::{arithmetic::FieldElement, NonZeroScalar};
use core::{cmp, fmt};
use ecdsa_core::signature::Result;
use sha2::{Digest, Sha256};
const AUX_TAG: &[u8] = b"BIP0340/aux";
const NONCE_TAG: &[u8] = b"BIP0340/nonce";
const CHALLENGE_TAG: &[u8] = b"BIP0340/challenge";
#[derive(Copy, Clone)]
pub struct Signature {
bytes: [u8; Self::BYTE_SIZE],
r: FieldElement,
s: NonZeroScalar,
}
impl Signature {
pub const BYTE_SIZE: usize = 64;
pub fn as_bytes(&self) -> &[u8; Self::BYTE_SIZE] {
&self.bytes
}
fn r(&self) -> &FieldElement {
&self.r
}
fn s(&self) -> &NonZeroScalar {
&self.s
}
fn split(&self) -> (&FieldElement, &NonZeroScalar) {
(self.r(), self.s())
}
}
impl AsRef<[u8]> for Signature {
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl Eq for Signature {}
impl PartialEq for Signature {
fn eq(&self, other: &Self) -> bool {
self.bytes == other.bytes
}
}
impl PartialOrd for Signature {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Signature {
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.bytes.cmp(&other.bytes)
}
}
impl TryFrom<&[u8]> for Signature {
type Error = Error;
fn try_from(bytes: &[u8]) -> Result<Signature> {
let bytes: [u8; Self::BYTE_SIZE] = bytes.try_into().map_err(|_| Error::new())?;
let (r_bytes, s_bytes) = bytes.split_at(Self::BYTE_SIZE / 2);
let r: FieldElement =
Option::from(FieldElement::from_bytes(r_bytes.into())).ok_or_else(Error::new)?;
if r.is_zero().into() {
return Err(Error::new());
}
let s = NonZeroScalar::try_from(s_bytes).map_err(|_| Error::new())?;
Ok(Self { bytes, r, s })
}
}
impl fmt::Debug for Signature {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.bytes.fmt(f)
}
}
impl signature::Signature for Signature {
fn from_bytes(bytes: &[u8]) -> Result<Self> {
bytes.try_into()
}
}
impl signature::PrehashSignature for Signature {
type Digest = Sha256;
}
fn tagged_hash(tag: &[u8]) -> Sha256 {
let tag_hash = Sha256::digest(tag);
let mut digest = Sha256::new();
digest.update(&tag_hash);
digest.update(&tag_hash);
digest
}
#[cfg(test)]
mod tests {
use super::{signature::Signature as _, Signature, SigningKey, VerifyingKey};
use hex_literal::hex;
struct SignVector {
index: u8,
secret_key: [u8; 32],
public_key: [u8; 32],
aux_rand: [u8; 32],
message: [u8; 32],
signature: [u8; 64],
}
const BIP340_SIGN_VECTORS: &[SignVector] = &[
SignVector {
index: 0,
secret_key: hex!("0000000000000000000000000000000000000000000000000000000000000003"),
public_key: hex!("F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9"),
aux_rand: hex!("0000000000000000000000000000000000000000000000000000000000000000"),
message: hex!("0000000000000000000000000000000000000000000000000000000000000000"),
signature: hex!(
"E907831F80848D1069A5371B402410364BDF1C5F8307B0084C55F1CE2DCA8215
25F66A4A85EA8B71E482A74F382D2CE5EBEEE8FDB2172F477DF4900D310536C0"
),
},
SignVector {
index: 1,
secret_key: hex!("B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF"),
public_key: hex!("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"),
aux_rand: hex!("0000000000000000000000000000000000000000000000000000000000000001"),
message: hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"),
signature: hex!(
"6896BD60EEAE296DB48A229FF71DFE071BDE413E6D43F917DC8DCF8C78DE3341
8906D11AC976ABCCB20B091292BFF4EA897EFCB639EA871CFA95F6DE339E4B0A"
),
},
SignVector {
index: 2,
secret_key: hex!("C90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B14E5C9"),
public_key: hex!("DD308AFEC5777E13121FA72B9CC1B7CC0139715309B086C960E18FD969774EB8"),
aux_rand: hex!("C87AA53824B4D7AE2EB035A2B5BBBCCC080E76CDC6D1692C4B0B62D798E6D906"),
message: hex!("7E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C"),
signature: hex!(
"5831AAEED7B44BB74E5EAB94BA9D4294C49BCF2A60728D8B4C200F50DD313C1B
AB745879A5AD954A72C45A91C3A51D3C7ADEA98D82F8481E0E1E03674A6F3FB7"
),
},
SignVector {
index: 3,
secret_key: hex!("0B432B2677937381AEF05BB02A66ECD012773062CF3FA2549E44F58ED2401710"),
public_key: hex!("25D1DFF95105F5253C4022F628A996AD3A0D95FBF21D468A1B33F8C160D8F517"),
aux_rand: hex!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"),
message: hex!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"),
signature: hex!(
"7EB0509757E246F19449885651611CB965ECC1A187DD51B64FDA1EDC9637D5EC
97582B9CB13DB3933705B32BA982AF5AF25FD78881EBB32771FC5922EFC66EA3"
),
},
];
#[test]
fn bip340_sign_vectors() {
for vector in BIP340_SIGN_VECTORS {
let sk = SigningKey::from_bytes(&vector.secret_key).unwrap();
assert_eq!(sk.verifying_key().to_bytes().as_slice(), &vector.public_key);
let sig = sk
.try_sign_prehashed(&vector.message, &vector.aux_rand)
.unwrap_or_else(|_| {
panic!(
"low-level Schnorr signing failure for index {}",
vector.index
)
});
assert_eq!(
&vector.signature,
sig.as_ref(),
"wrong signature for index {}",
vector.index
);
}
}
struct VerifyVector {
index: u8,
public_key: [u8; 32],
message: [u8; 32],
signature: [u8; 64],
valid: bool,
}
const BIP340_VERIFY_VECTORS: &[VerifyVector] = &[
VerifyVector {
index: 4,
public_key: hex!("D69C3509BB99E412E68B0FE8544E72837DFA30746D8BE2AA65975F29D22DC7B9"),
message: hex!("4DF3C3F68FCC83B27E9D42C90431A72499F17875C81A599B566C9889B9696703"),
signature: hex!(
"00000000000000000000003B78CE563F89A0ED9414F5AA28AD0D96D6795F9C63
76AFB1548AF603B3EB45C9F8207DEE1060CB71C04E80F593060B07D28308D7F4"
),
valid: true,
},
VerifyVector {
index: 5,
public_key: hex!("EEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34"),
message: hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"),
signature: hex!(
"6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E177769
69E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B"
),
valid: false,
},
VerifyVector {
index: 6,
public_key: hex!("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"),
message: hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"),
signature: hex!(
"FFF97BD5755EEEA420453A14355235D382F6472F8568A18B2F057A1460297556
3CC27944640AC607CD107AE10923D9EF7A73C643E166BE5EBEAFA34B1AC553E2"
),
valid: false,
},
VerifyVector {
index: 7,
public_key: hex!("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"),
message: hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"),
signature: hex!(
"1FA62E331EDBC21C394792D2AB1100A7B432B013DF3F6FF4F99FCB33E0E1515F
28890B3EDB6E7189B630448B515CE4F8622A954CFE545735AAEA5134FCCDB2BD"
),
valid: false,
},
VerifyVector {
index: 8,
public_key: hex!("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"),
message: hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"),
signature: hex!(
"6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E177769
961764B3AA9B2FFCB6EF947B6887A226E8D7C93E00C5ED0C1834FF0D0C2E6DA6"
),
valid: false,
},
VerifyVector {
index: 9,
public_key: hex!("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"),
message: hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"),
signature: hex!(
"0000000000000000000000000000000000000000000000000000000000000000
123DDA8328AF9C23A94C1FEECFD123BA4FB73476F0D594DCB65C6425BD186051"
),
valid: false,
},
VerifyVector {
index: 10,
public_key: hex!("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"),
message: hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"),
signature: hex!(
"0000000000000000000000000000000000000000000000000000000000000001
7615FBAF5AE28864013C099742DEADB4DBA87F11AC6754F93780D5A1837CF197"
),
valid: false,
},
VerifyVector {
index: 11,
public_key: hex!("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"),
message: hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"),
signature: hex!(
"4A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D
69E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B"
),
valid: false,
},
VerifyVector {
index: 12,
public_key: hex!("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"),
message: hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"),
signature: hex!(
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
69E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B"
),
valid: false,
},
VerifyVector {
index: 13,
public_key: hex!("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"),
message: hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"),
signature: hex!(
"6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E177769
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"
),
valid: false,
},
VerifyVector {
index: 14,
public_key: hex!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30"),
message: hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"),
signature: hex!(
"6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E177769
69E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B"
),
valid: false,
},
];
#[test]
fn bip340_verify_vectors() {
for vector in BIP340_VERIFY_VECTORS {
let valid = match (
VerifyingKey::from_bytes(&vector.public_key),
Signature::from_bytes(&vector.signature),
) {
(Ok(pk), Ok(sig)) => pk.verify_prehashed(&vector.message, &sig).is_ok(),
_ => false,
};
assert_eq!(
vector.valid, valid,
"incorrect validation for index {}",
vector.index
);
}
}
}