1use crate::{
2 BatchEntry, BatchVerifier, Secret,
3 ed25519::core::{self as ed_core, VerificationKey},
4};
5#[cfg(not(feature = "std"))]
6use alloc::borrow::{Cow, ToOwned};
7#[cfg(all(not(feature = "std"), feature = "arbitrary"))]
8use alloc::vec::Vec;
9use bytes::BufMut;
10use commonware_codec::{Buf, Error as CodecError, FixedArray, FixedSize, Read, ReadExt, Write};
11use commonware_formatting::Hex;
12use commonware_math::algebra::Random;
13use commonware_parallel::Strategy;
14use commonware_utils::{Array, Span, union_unique};
15use core::{
16 fmt::{Debug, Display},
17 hash::Hash,
18 ops::Deref,
19};
20use rand_core::CryptoRng;
21#[cfg(feature = "std")]
22use std::borrow::{Cow, ToOwned};
23use zeroize::Zeroizing;
24
25const CURVE_NAME: &str = "ed25519";
26const PRIVATE_KEY_LENGTH: usize = 32;
27const PUBLIC_KEY_LENGTH: usize = 32;
28const SIGNATURE_LENGTH: usize = 64;
29
30#[derive(Clone, Debug)]
32pub struct PrivateKey {
33 key: Secret<ed_core::SigningKey>,
34}
35
36impl crate::PrivateKey for PrivateKey {}
37
38impl crate::Signer for PrivateKey {
39 type Signature = Signature;
40 type PublicKey = PublicKey;
41
42 fn sign(&self, namespace: &[u8], msg: &[u8]) -> Self::Signature {
43 self.sign_inner(Some(namespace), msg)
44 }
45
46 fn public_key(&self) -> Self::PublicKey {
47 self.key.expose(|key| Self::PublicKey {
48 key: key.verification_key().to_owned(),
49 })
50 }
51}
52
53impl PrivateKey {
54 #[inline(always)]
55 fn sign_inner(&self, namespace: Option<&[u8]>, msg: &[u8]) -> Signature {
56 let payload = namespace
57 .map(|namespace| Cow::Owned(union_unique(namespace, msg)))
58 .unwrap_or_else(|| Cow::Borrowed(msg));
59 self.key.expose(|key| Signature::from(key.sign(&payload)))
60 }
61}
62
63impl Random for PrivateKey {
64 fn random(rng: impl CryptoRng) -> Self {
65 let key = ed_core::SigningKey::new(rng);
66 Self {
67 key: Secret::new(key),
68 }
69 }
70}
71
72impl Write for PrivateKey {
73 fn write(&self, buf: &mut impl BufMut) {
74 self.key.expose(|key| key.as_bytes().write(buf));
75 }
76}
77
78impl Read for PrivateKey {
79 type Cfg = ();
80
81 fn read_cfg(buf: &mut impl Buf, _: &()) -> Result<Self, CodecError> {
82 let raw = Zeroizing::new(<[u8; Self::SIZE]>::read(buf)?);
83 let key = ed_core::SigningKey::from(*raw);
84 Ok(Self {
85 key: Secret::new(key),
86 })
87 }
88}
89
90impl FixedSize for PrivateKey {
91 const SIZE: usize = PRIVATE_KEY_LENGTH;
92}
93
94impl From<ed_core::SigningKey> for PrivateKey {
95 fn from(key: ed_core::SigningKey) -> Self {
96 Self {
97 key: Secret::new(key),
98 }
99 }
100}
101
102impl Display for PrivateKey {
103 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
104 write!(f, "{:?}", self)
105 }
106}
107
108#[cfg(feature = "arbitrary")]
109impl arbitrary::Arbitrary<'_> for PrivateKey {
110 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
111 use rand::{SeedableRng, rngs::StdRng};
112
113 let mut rand = StdRng::from_seed(u.arbitrary::<[u8; 32]>()?);
114 Ok(Self::random(&mut rand))
115 }
116}
117
118#[cfg(test)]
119impl PartialEq for PrivateKey {
120 fn eq(&self, other: &Self) -> bool {
121 self.key
122 .expose(|key1| other.key.expose(|key2| key1.as_bytes() == key2.as_bytes()))
123 }
124}
125
126#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, FixedArray)]
131pub struct PublicKey {
132 key: ed_core::VerificationKey,
133}
134
135impl From<PrivateKey> for PublicKey {
136 fn from(value: PrivateKey) -> Self {
137 value.key.expose(|key| Self {
138 key: key.verification_key(),
139 })
140 }
141}
142
143impl crate::PublicKey for PublicKey {}
144
145impl crate::Verifier for PublicKey {
146 type Signature = Signature;
147
148 fn verify(&self, namespace: &[u8], msg: &[u8], sig: &Self::Signature) -> bool {
149 self.verify_inner(Some(namespace), msg, sig)
150 }
151}
152
153impl BatchVerifier for PublicKey {
154 fn verify_batch<'a, R, T, F>(
155 rng: &mut R,
156 items: &'a [T],
157 project: F,
158 strategy: &impl Strategy,
159 ) -> bool
160 where
161 R: CryptoRng,
162 T: Sync,
163 F: Fn(usize, &'a T) -> BatchEntry<'a, Self> + Sync,
164 {
165 ed_core::batch::verify_projected(
166 rng,
167 items,
168 |i, item| {
169 let entry = project(i, item);
170 (
171 &entry.public_key.key,
172 ed_core::Signature::from(entry.signature.raw),
173 Some(entry.namespace),
174 entry.message,
175 )
176 },
177 strategy,
178 )
179 .is_ok()
180 }
181}
182
183impl PublicKey {
184 #[inline(always)]
185 fn verify_inner(&self, namespace: Option<&[u8]>, msg: &[u8], sig: &Signature) -> bool {
186 let payload = namespace
187 .map(|namespace| Cow::Owned(union_unique(namespace, msg)))
188 .unwrap_or_else(|| Cow::Borrowed(msg));
189 self.key
190 .verify(&ed_core::Signature::from(sig.raw), &payload)
191 .is_ok()
192 }
193}
194
195impl Write for PublicKey {
196 fn write(&self, buf: &mut impl BufMut) {
197 self.key.as_bytes().write(buf);
198 }
199}
200
201impl Read for PublicKey {
202 type Cfg = ();
203
204 fn read_cfg(buf: &mut impl Buf, _: &()) -> Result<Self, CodecError> {
205 let raw = <[u8; Self::SIZE]>::read(buf)?;
206 let result = VerificationKey::try_from(raw);
207 #[cfg(feature = "std")]
208 let key = result.map_err(|e| CodecError::Wrapped(CURVE_NAME, e.into()))?;
209 #[cfg(not(feature = "std"))]
210 let key = result
211 .map_err(|e| CodecError::Wrapped(CURVE_NAME, alloc::format!("{:?}", e).into()))?;
212
213 Ok(Self { key })
214 }
215}
216
217impl FixedSize for PublicKey {
218 const SIZE: usize = PUBLIC_KEY_LENGTH;
219}
220
221impl Span for PublicKey {}
222
223impl Array for PublicKey {}
224
225impl AsRef<[u8]> for PublicKey {
226 fn as_ref(&self) -> &[u8] {
227 self.key.as_ref()
228 }
229}
230
231impl Deref for PublicKey {
232 type Target = [u8];
233 fn deref(&self) -> &[u8] {
234 self.key.as_ref()
235 }
236}
237
238impl Debug for PublicKey {
239 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
240 write!(f, "{}", Hex(self))
241 }
242}
243
244impl Display for PublicKey {
245 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
246 write!(f, "{}", Hex(self))
247 }
248}
249
250#[cfg(feature = "arbitrary")]
251impl arbitrary::Arbitrary<'_> for PublicKey {
252 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
253 use crate::Signer;
254 use commonware_math::algebra::Random;
255 use rand::{SeedableRng, rngs::StdRng};
256
257 let mut rand = StdRng::from_seed(u.arbitrary::<[u8; 32]>()?);
258 let private_key = PrivateKey::random(&mut rand);
259 Ok(private_key.public_key())
260 }
261}
262
263#[derive(Clone, Eq, Hash, Ord, PartialEq, PartialOrd, FixedArray)]
275pub struct Signature {
276 raw: [u8; SIGNATURE_LENGTH],
277}
278
279impl crate::Signature for Signature {}
280
281impl Write for Signature {
282 fn write(&self, buf: &mut impl BufMut) {
283 self.raw.write(buf);
284 }
285}
286
287impl Read for Signature {
288 type Cfg = ();
289
290 fn read_cfg(buf: &mut impl Buf, _: &()) -> Result<Self, CodecError> {
291 let raw = <[u8; Self::SIZE]>::read(buf)?;
292 Ok(Self { raw })
293 }
294}
295
296impl FixedSize for Signature {
297 const SIZE: usize = SIGNATURE_LENGTH;
298}
299
300impl Span for Signature {}
301
302impl Array for Signature {}
303
304impl AsRef<[u8]> for Signature {
305 fn as_ref(&self) -> &[u8] {
306 &self.raw
307 }
308}
309
310impl Deref for Signature {
311 type Target = [u8];
312 fn deref(&self) -> &[u8] {
313 &self.raw
314 }
315}
316
317impl From<ed_core::Signature> for Signature {
318 fn from(value: ed_core::Signature) -> Self {
319 let raw = value.to_bytes();
320 Self { raw }
321 }
322}
323
324impl Debug for Signature {
325 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
326 write!(f, "{}", Hex(&self.raw))
327 }
328}
329
330impl Display for Signature {
331 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
332 write!(f, "{}", Hex(&self.raw))
333 }
334}
335
336#[cfg(feature = "arbitrary")]
337impl arbitrary::Arbitrary<'_> for Signature {
338 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
339 use crate::Signer;
340 use commonware_math::algebra::Random;
341 use rand::{SeedableRng, rngs::StdRng};
342
343 let mut rand = StdRng::from_seed(u.arbitrary::<[u8; 32]>()?);
344 let private_key = PrivateKey::random(&mut rand);
345 let len = u.arbitrary::<usize>()? % 256;
346 let message = u
347 .arbitrary_iter()?
348 .take(len)
349 .collect::<Result<Vec<_>, _>>()?;
350
351 Ok(private_key.sign(&[], &message))
352 }
353}
354
355#[cfg(test)]
357mod tests {
358 use super::*;
359 use crate::Signer as _;
360 #[cfg(not(feature = "std"))]
361 use alloc::vec::Vec;
362 use commonware_codec::{DecodeExt, Encode};
363 use commonware_math::algebra::Random;
364 use commonware_parallel::{Sequential, mocks::explore};
365 use commonware_utils::test_rng;
366
367 fn test_sign_and_verify(
368 private_key: PrivateKey,
369 public_key: PublicKey,
370 message: &[u8],
371 signature: Signature,
372 ) {
373 let computed_signature = private_key.sign_inner(None, message);
374 assert_eq!(computed_signature, signature);
375 assert!(public_key.verify_inner(None, message, &computed_signature));
376 }
377
378 fn parse_private_key(private_key: &str) -> PrivateKey {
379 PrivateKey::decode(commonware_formatting::from_hex(private_key).unwrap()).unwrap()
380 }
381
382 fn parse_public_key(public_key: &str) -> PublicKey {
383 PublicKey::decode(commonware_formatting::from_hex(public_key).unwrap()).unwrap()
384 }
385
386 fn parse_signature(signature: &str) -> Signature {
387 Signature::decode(commonware_formatting::from_hex(signature).unwrap()).unwrap()
388 }
389
390 fn vector_1() -> (PrivateKey, PublicKey, Vec<u8>, Signature) {
391 (
392 parse_private_key(
394 "
395 9d61b19deffd5a60ba844af492ec2cc4
396 4449c5697b326919703bac031cae7f60
397 ",
398 ),
399 parse_public_key(
401 "
402 d75a980182b10ab7d54bfed3c964073a
403 0ee172f3daa62325af021a68f707511a
404 ",
405 ),
406 b"".to_vec(),
408 parse_signature(
410 "
411 e5564300c360ac729086e2cc806e828a
412 84877f1eb8e5d974d873e06522490155
413 5fb8821590a33bacc61e39701cf9b46b
414 d25bf5f0595bbe24655141438e7a100b
415 ",
416 ),
417 )
418 }
419
420 fn vector_2() -> (PrivateKey, PublicKey, Vec<u8>, Signature) {
421 (
422 parse_private_key(
424 "
425 4ccd089b28ff96da9db6c346ec114e0f
426 5b8a319f35aba624da8cf6ed4fb8a6fb
427 ",
428 ),
429 parse_public_key(
431 "
432 3d4017c3e843895a92b70aa74d1b7ebc
433 9c982ccf2ec4968cc0cd55f12af4660c
434 ",
435 ),
436 [0x72].to_vec(),
438 parse_signature(
440 "
441 92a009a9f0d4cab8720e820b5f642540
442 a2b27b5416503f8fb3762223ebdb69da
443 085ac1e43e15996e458f3613d0f11d8c
444 387b2eaeb4302aeeb00d291612bb0c00
445 ",
446 ),
447 )
448 }
449
450 #[test]
451 fn test_codec_private_key() {
452 let private_key = parse_private_key(
453 "
454 9d61b19deffd5a60ba844af492ec2cc4
455 4449c5697b326919703bac031cae7f60
456 ",
457 );
458 let encoded = private_key.encode();
459 assert_eq!(encoded.len(), PRIVATE_KEY_LENGTH);
460 let decoded = PrivateKey::decode(encoded).unwrap();
461 assert_eq!(private_key, decoded);
462 }
463
464 #[test]
465 fn test_codec_public_key() {
466 let public_key = parse_public_key(
467 "
468 d75a980182b10ab7d54bfed3c964073a
469 0ee172f3daa62325af021a68f707511a
470 ",
471 );
472 let encoded = public_key.encode();
473 assert_eq!(encoded.len(), PUBLIC_KEY_LENGTH);
474 let decoded = PublicKey::decode(encoded).unwrap();
475 assert_eq!(public_key, decoded);
476 }
477
478 #[test]
479 fn test_codec_signature() {
480 let signature = parse_signature(
481 "
482 e5564300c360ac729086e2cc806e828a
483 84877f1eb8e5d974d873e06522490155
484 5fb8821590a33bacc61e39701cf9b46b
485 d25bf5f0595bbe24655141438e7a100b
486 ",
487 );
488 let encoded = signature.encode();
489 assert_eq!(encoded.len(), SIGNATURE_LENGTH);
490 let decoded = Signature::decode(encoded).unwrap();
491 assert_eq!(signature, decoded);
492 }
493
494 #[test]
495 fn rfc8032_test_vector_1() {
496 let (private_key, public_key, message, signature) = vector_1();
497 test_sign_and_verify(private_key, public_key, &message, signature)
498 }
499
500 #[test]
502 #[should_panic]
503 fn bad_signature() {
504 let (private_key, public_key, message, _) = vector_1();
505 let private_key_2 = PrivateKey::random(test_rng());
506 let bad_signature = private_key_2.sign_inner(None, &message);
507 test_sign_and_verify(private_key, public_key, &message, bad_signature);
508 }
509
510 #[test]
512 #[should_panic]
513 fn different_message() {
514 let (private_key, public_key, _, signature) = vector_1();
515 let different_message = b"this is a different message".to_vec();
516 test_sign_and_verify(private_key, public_key, &different_message, signature);
517 }
518
519 #[test]
520 fn rfc8032_test_vector_2() {
521 let (private_key, public_key, message, signature) = vector_2();
522 test_sign_and_verify(private_key, public_key, &message, signature)
523 }
524
525 #[test]
526 fn rfc8032_test_vector_3() {
527 let private_key = parse_private_key(
528 "
529 c5aa8df43f9f837bedb7442f31dcb7b1
530 66d38535076f094b85ce3a2e0b4458f7
531 ",
532 );
533 let public_key = parse_public_key(
534 "
535 fc51cd8e6218a1a38da47ed00230f058
536 0816ed13ba3303ac5deb911548908025
537 ",
538 );
539 let message = commonware_formatting::hex!("0xaf82");
540 let signature = parse_signature(
541 "
542 6291d657deec24024827e69c3abe01a3
543 0ce548a284743a445e3680d7db5ac3ac
544 18ff9b538d16f290ae67f760984dc659
545 4a7c15e9716ed28dc027beceea1ec40a
546 ",
547 );
548 test_sign_and_verify(private_key, public_key, &message, signature)
549 }
550
551 #[test]
552 fn rfc8032_test_vector_1024() {
553 let private_key = parse_private_key(
554 "
555 f5e5767cf153319517630f226876b86c
556 8160cc583bc013744c6bf255f5cc0ee5
557 ",
558 );
559 let public_key = parse_public_key(
560 "
561 278117fc144c72340f67d0f2316e8386
562 ceffbf2b2428c9c51fef7c597f1d426e
563 ",
564 );
565 let message = commonware_formatting::from_hex(
566 "
567 08b8b2b733424243760fe426a4b54908
568 632110a66c2f6591eabd3345e3e4eb98
569 fa6e264bf09efe12ee50f8f54e9f77b1
570 e355f6c50544e23fb1433ddf73be84d8
571 79de7c0046dc4996d9e773f4bc9efe57
572 38829adb26c81b37c93a1b270b20329d
573 658675fc6ea534e0810a4432826bf58c
574 941efb65d57a338bbd2e26640f89ffbc
575 1a858efcb8550ee3a5e1998bd177e93a
576 7363c344fe6b199ee5d02e82d522c4fe
577 ba15452f80288a821a579116ec6dad2b
578 3b310da903401aa62100ab5d1a36553e
579 06203b33890cc9b832f79ef80560ccb9
580 a39ce767967ed628c6ad573cb116dbef
581 efd75499da96bd68a8a97b928a8bbc10
582 3b6621fcde2beca1231d206be6cd9ec7
583 aff6f6c94fcd7204ed3455c68c83f4a4
584 1da4af2b74ef5c53f1d8ac70bdcb7ed1
585 85ce81bd84359d44254d95629e9855a9
586 4a7c1958d1f8ada5d0532ed8a5aa3fb2
587 d17ba70eb6248e594e1a2297acbbb39d
588 502f1a8c6eb6f1ce22b3de1a1f40cc24
589 554119a831a9aad6079cad88425de6bd
590 e1a9187ebb6092cf67bf2b13fd65f270
591 88d78b7e883c8759d2c4f5c65adb7553
592 878ad575f9fad878e80a0c9ba63bcbcc
593 2732e69485bbc9c90bfbd62481d9089b
594 eccf80cfe2df16a2cf65bd92dd597b07
595 07e0917af48bbb75fed413d238f5555a
596 7a569d80c3414a8d0859dc65a46128ba
597 b27af87a71314f318c782b23ebfe808b
598 82b0ce26401d2e22f04d83d1255dc51a
599 ddd3b75a2b1ae0784504df543af8969b
600 e3ea7082ff7fc9888c144da2af58429e
601 c96031dbcad3dad9af0dcbaaaf268cb8
602 fcffead94f3c7ca495e056a9b47acdb7
603 51fb73e666c6c655ade8297297d07ad1
604 ba5e43f1bca32301651339e22904cc8c
605 42f58c30c04aafdb038dda0847dd988d
606 cda6f3bfd15c4b4c4525004aa06eeff8
607 ca61783aacec57fb3d1f92b0fe2fd1a8
608 5f6724517b65e614ad6808d6f6ee34df
609 f7310fdc82aebfd904b01e1dc54b2927
610 094b2db68d6f903b68401adebf5a7e08
611 d78ff4ef5d63653a65040cf9bfd4aca7
612 984a74d37145986780fc0b16ac451649
613 de6188a7dbdf191f64b5fc5e2ab47b57
614 f7f7276cd419c17a3ca8e1b939ae49e4
615 88acba6b965610b5480109c8b17b80e1
616 b7b750dfc7598d5d5011fd2dcc5600a3
617 2ef5b52a1ecc820e308aa342721aac09
618 43bf6686b64b2579376504ccc493d97e
619 6aed3fb0f9cd71a43dd497f01f17c0e2
620 cb3797aa2a2f256656168e6c496afc5f
621 b93246f6b1116398a346f1a641f3b041
622 e989f7914f90cc2c7fff357876e506b5
623 0d334ba77c225bc307ba537152f3f161
624 0e4eafe595f6d9d90d11faa933a15ef1
625 369546868a7f3a45a96768d40fd9d034
626 12c091c6315cf4fde7cb68606937380d
627 b2eaaa707b4c4185c32eddcdd306705e
628 4dc1ffc872eeee475a64dfac86aba41c
629 0618983f8741c5ef68d3a101e8a3b8ca
630 c60c905c15fc910840b94c00a0b9d0
631 ",
632 )
633 .unwrap();
634 let signature = parse_signature(
635 "
636 0aab4c900501b3e24d7cdf4663326a3a
637 87df5e4843b2cbdb67cbf6e460fec350
638 aa5371b1508f9f4528ecea23c436d94b
639 5e8fcd4f681e30a6ac00a9704a188a03
640 ",
641 );
642 test_sign_and_verify(private_key, public_key, &message, signature)
643 }
644
645 #[test]
646 fn rfc8032_test_vector_sha() {
647 let private_key = commonware_formatting::from_hex(
648 "
649 833fe62409237b9d62ec77587520911e
650 9a759cec1d19755b7da901b96dca3d42
651 ",
652 )
653 .unwrap();
654 let public_key = commonware_formatting::from_hex(
655 "
656 ec172b93ad5e563bf4932c70e1245034
657 c35467ef2efd4d64ebf819683467e2bf
658 ",
659 )
660 .unwrap();
661 let message = commonware_formatting::from_hex(
662 "
663 ddaf35a193617abacc417349ae204131
664 12e6fa4e89a97ea20a9eeee64b55d39a
665 2192992a274fc1a836ba3c23a3feebbd
666 454d4423643ce80e2a9ac94fa54ca49f
667 ",
668 )
669 .unwrap();
670 let signature = commonware_formatting::from_hex(
671 "
672 dc2a4459e7369633a52b1bf277839a00
673 201009a3efbf3ecb69bea2186c26b589
674 09351fc9ac90b3ecfdfbc7c66431e030
675 3dca179c138ac17ad9bef1177331a704
676 ",
677 )
678 .unwrap();
679 test_sign_and_verify(
680 PrivateKey::decode(private_key).unwrap(),
681 PublicKey::decode(public_key).unwrap(),
682 &message,
683 Signature::decode(signature).unwrap(),
684 )
685 }
686
687 fn verify_raw_vectors(items: &[(PrivateKey, PublicKey, Vec<u8>, Signature)]) -> bool {
688 ed_core::batch::verify_projected(
689 &mut test_rng(),
690 items,
691 |_, (_, public_key, message, signature)| {
692 (
693 &public_key.key,
694 ed_core::Signature::from(signature.raw),
695 None,
696 message.as_slice(),
697 )
698 },
699 &Sequential,
700 )
701 .is_ok()
702 }
703
704 #[test]
705 fn batch_verify_valid() {
706 assert!(verify_raw_vectors(&[vector_1(), vector_2()]));
707 }
708
709 #[test]
710 fn batch_verify_invalid() {
711 let mut v2 = vector_2();
712 v2.3.raw[3] = 0xff;
713 assert!(!verify_raw_vectors(&[vector_1(), v2]));
714 }
715
716 #[test]
717 fn batch_verify_empty() {
718 let entries: [BatchEntry<'_, PublicKey>; 0] = [];
719 assert!(!PublicKey::verify_batch(
720 &mut test_rng(),
721 &entries,
722 |_, entry| *entry,
723 &Sequential
724 ));
725 }
726
727 #[test]
728 fn batch_framing_matches_union_unique() {
729 let key = PrivateKey::random(test_rng());
732 let public_key = key.public_key();
733 let message = b"message";
734 for len in [0, 1, 127, 128, 255, 16383, 16384] {
735 let namespace = vec![42; len];
736 let signature = key.sign_inner(None, &union_unique(&namespace, message));
737 for supplied_namespace in [namespace.as_slice(), b"other"] {
738 let entries = [BatchEntry {
739 namespace: supplied_namespace,
740 message,
741 public_key: &public_key,
742 signature: &signature,
743 }];
744 assert_eq!(
745 PublicKey::verify_batch(
746 &mut test_rng(),
747 &entries,
748 |_, entry| *entry,
749 &Sequential
750 ),
751 supplied_namespace == namespace,
752 );
753 }
754
755 if !namespace.is_empty() {
757 let moved_message = [&namespace[len - 1..], message].concat();
758 let entries = [BatchEntry {
759 namespace: &namespace[..len - 1],
760 message: &moved_message,
761 public_key: &public_key,
762 signature: &signature,
763 }];
764 assert!(!PublicKey::verify_batch(
765 &mut test_rng(),
766 &entries,
767 |_, entry| *entry,
768 &Sequential
769 ));
770 }
771 }
772 }
773
774 #[test]
775 fn projected_batch_borrows_records() {
776 fn verify(
777 records: &[(Vec<u8>, Signature, usize)],
778 namespace: &[u8],
779 publics: &[PublicKey; 2],
780 strategy: &impl Strategy,
781 ) -> bool {
782 PublicKey::verify_batch(
783 &mut test_rng(),
784 records,
785 |index, record| {
786 assert!(core::ptr::eq(record, &records[index]));
787 BatchEntry {
788 namespace,
789 message: &record.0,
790 public_key: &publics[record.2],
791 signature: &record.1,
792 }
793 },
794 strategy,
795 )
796 }
797
798 let mut rng = test_rng();
800 let keys = [PrivateKey::random(&mut rng), PrivateKey::random(&mut rng)];
801 let publics = keys.each_ref().map(|key| key.public_key());
802 let namespace = b"namespace";
803 let mut records: Vec<_> = (0..25)
804 .map(|i| {
805 let message = vec![i as u8; if i % 3 == 0 { 0 } else { 1024 }];
806 let signature = keys[i % 2].sign(namespace, &message);
807 (message, signature, i % 2)
808 })
809 .collect();
810
811 assert!(explore(|strategy| verify(
813 &records, namespace, &publics, strategy
814 )));
815
816 for index in 0..records.len() {
818 records[index].0.push(0);
819 assert!(!explore(|strategy| verify(
820 &records, namespace, &publics, strategy
821 )));
822 records[index].0.pop();
823 }
824
825 let mut invalid = records;
827 invalid[24].1.raw[63] |= 0x80;
828 assert!(!explore(|strategy| verify(
829 &invalid, namespace, &publics, strategy
830 )));
831
832 let empty: [BatchEntry<'_, PublicKey>; 0] = [];
834 assert!(!PublicKey::verify_batch(
835 &mut rng,
836 &empty,
837 |_, entry| *entry,
838 &Sequential
839 ));
840 }
841
842 #[test]
843 fn projected_batch_indexes_zero_sized_items() {
844 fn verify(
845 messages: &[Vec<u8>],
846 signatures: &[Signature],
847 public_keys: &[PublicKey],
848 strategy: &impl Strategy,
849 ) -> bool {
850 let items = vec![(); messages.len()];
851 PublicKey::verify_batch(
852 &mut test_rng(),
853 &items,
854 |index, ()| BatchEntry {
855 namespace: b"namespace",
856 message: &messages[index],
857 public_key: &public_keys[index % public_keys.len()],
858 signature: &signatures[index],
859 },
860 strategy,
861 )
862 }
863
864 let mut rng = test_rng();
866 let keys = [PrivateKey::random(&mut rng), PrivateKey::random(&mut rng)];
867 let public_keys = keys.each_ref().map(|key| key.public_key());
868 let mut messages: Vec<_> = (0..25).map(|i| vec![i as u8; 32]).collect();
869 let signatures: Vec<_> = messages
870 .iter()
871 .enumerate()
872 .map(|(i, message)| keys[i % keys.len()].sign(b"namespace", message))
873 .collect();
874
875 assert!(explore(|strategy| verify(
877 &messages,
878 &signatures,
879 &public_keys,
880 strategy
881 )));
882
883 for index in 0..messages.len() {
885 messages[index][0] ^= 1;
886 assert!(!explore(|strategy| verify(
887 &messages,
888 &signatures,
889 &public_keys,
890 strategy
891 )));
892 messages[index][0] ^= 1;
893 }
894 }
895
896 #[test]
897 fn test_zero_signature_fails() {
898 let (_, public_key, message, _) = vector_1();
899 let zero_sig = Signature::decode(vec![0u8; Signature::SIZE]).unwrap();
900 assert!(!public_key.verify_inner(None, &message, &zero_sig));
901 }
902
903 #[test]
904 fn test_high_s_fails() {
905 let (_, public_key, message, signature) = vector_1();
906 let mut bad_signature = signature.to_vec();
907 bad_signature[63] |= 0x80; let bad_signature = Signature::decode(bad_signature).unwrap();
909 assert!(!public_key.verify_inner(None, &message, &bad_signature));
910 }
911
912 #[test]
913 fn test_invalid_r_fails() {
914 let (_, public_key, message, signature) = vector_1();
915 let mut bad_signature = signature.to_vec();
916 for b in bad_signature.iter_mut().take(32) {
917 *b = 0xff; }
919 let bad_signature = Signature::decode(bad_signature).unwrap();
920 assert!(!public_key.verify_inner(None, &message, &bad_signature));
921 }
922
923 #[test]
924 fn test_from_signing_key() {
925 let signing_key = ed_core::SigningKey::new(test_rng());
926 let expected_public = signing_key.verification_key();
927 let private_key = PrivateKey::from(signing_key);
928 assert_eq!(private_key.public_key().key, expected_public);
929 }
930
931 #[test]
932 fn test_private_key_redacted() {
933 let private_key = PrivateKey::random(test_rng());
934 let debug = format!("{:?}", private_key);
935 let display = format!("{}", private_key);
936 assert!(debug.contains("REDACTED"));
937 assert!(display.contains("REDACTED"));
938 }
939
940 #[test]
941 fn test_from_private_key_to_public_key() {
942 let private_key = PrivateKey::random(test_rng());
943 assert_eq!(private_key.public_key(), PublicKey::from(private_key));
944 }
945
946 #[cfg(feature = "arbitrary")]
947 mod conformance {
948 use super::*;
949 use commonware_codec::conformance::CodecConformance;
950
951 commonware_conformance::conformance_tests! {
952 CodecConformance<PrivateKey>,
953 CodecConformance<PublicKey>,
954 CodecConformance<Signature>,
955 }
956 }
957}