Skip to main content

commonware_cryptography/ed25519/
scheme.rs

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/// Ed25519 Private Key.
31#[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/// Ed25519 Public Key.
127///
128/// Equality, ordering, and hashing use the original encoding. Distinct encodings of the same
129/// curve point are distinct keys.
130#[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/// Ed25519 Signature.
264///
265/// Signatures from honestly generated keys are *non-malleable*: an adversary
266/// with access to many messages and signatures, verifying against an honestly
267/// generated public key, cannot find a new signature which will verify, even by
268/// tampering or modifying the signatures that it has seen previously.
269///
270/// Like any signature, it's also not possible to have a signature that verifies against
271/// one message also verify against another. This property does not hold for maliciously
272/// generated public keys. In particular, it's possible to craft public keys (which would
273/// otherwise not be honestly generatable) for which a signature will verify against any message.
274#[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/// Test vectors sourced from https://datatracker.ietf.org/doc/html/rfc8032#section-7.1.
356#[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            // secret key
393            parse_private_key(
394                "
395                9d61b19deffd5a60ba844af492ec2cc4
396                4449c5697b326919703bac031cae7f60
397                ",
398            ),
399            // public key
400            parse_public_key(
401                "
402                d75a980182b10ab7d54bfed3c964073a
403                0ee172f3daa62325af021a68f707511a
404                ",
405            ),
406            // message
407            b"".to_vec(),
408            // signature
409            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            // secret key
423            parse_private_key(
424                "
425                4ccd089b28ff96da9db6c346ec114e0f
426                5b8a319f35aba624da8cf6ed4fb8a6fb
427                ",
428            ),
429            // public key
430            parse_public_key(
431                "
432                3d4017c3e843895a92b70aa74d1b7ebc
433                9c982ccf2ec4968cc0cd55f12af4660c
434                ",
435            ),
436            // message
437            [0x72].to_vec(),
438            // signature
439            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    // sanity check the test infra rejects bad signatures
501    #[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    // sanity check the test infra rejects non-matching messages
511    #[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        // Check streamed framing against raw signatures across namespace-length
730        // encoding boundaries.
731        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            // Moving a byte across the namespace boundary must invalidate the signature.
756            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        // Mix empty and large messages from repeated signers in an uneven batch.
799        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        // Every execution shape must verify the original borrowed records.
812        assert!(explore(|strategy| verify(
813            &records, namespace, &publics, strategy
814        )));
815
816        // Every entry must be checked, whichever batch holds it.
817        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        // A noncanonical scalar in the final record must invalidate the batch.
826        let mut invalid = records;
827        invalid[24].1.raw[63] |= 0x80;
828        assert!(!explore(|strategy| verify(
829            &invalid, namespace, &publics, strategy
830        )));
831
832        // Empty input must fail verification.
833        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        // Use an uneven batch whose unit items identify messages only by their original index.
865        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        // Every execution shape must resolve each original index to the matching signed message.
876        assert!(explore(|strategy| verify(
877            &messages,
878            &signatures,
879            &public_keys,
880            strategy
881        )));
882
883        // Changing each indexed message in turn must fail the whole batch.
884        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; // make S non-canonical
908        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; // invalid R component
918        }
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}