commonware_cryptography/ed25519/
scheme.rs

1use crate::{Array, BatchScheme, Error, Scheme};
2use commonware_utils::{hex, union_unique, SizedSerialize};
3use ed25519_consensus::{self, VerificationKey};
4use rand::{CryptoRng, Rng, RngCore};
5use std::borrow::Cow;
6use std::fmt::{Debug, Display};
7use std::hash::{Hash, Hasher};
8use std::ops::Deref;
9
10const PRIVATE_KEY_LENGTH: usize = 32;
11const PUBLIC_KEY_LENGTH: usize = 32;
12const SIGNATURE_LENGTH: usize = 64;
13
14/// Ed25519 Signer.
15#[derive(Clone)]
16pub struct Ed25519 {
17    signer: ed25519_consensus::SigningKey,
18    verifier: ed25519_consensus::VerificationKey,
19}
20
21impl Scheme for Ed25519 {
22    type PrivateKey = PrivateKey;
23    type PublicKey = PublicKey;
24    type Signature = Signature;
25
26    fn new<R: CryptoRng + Rng>(r: &mut R) -> Self {
27        let signer = ed25519_consensus::SigningKey::new(r);
28        let verifier = signer.verification_key();
29        Self { signer, verifier }
30    }
31
32    fn from(private_key: PrivateKey) -> Option<Self> {
33        let signer = private_key.key;
34        let verifier = signer.verification_key();
35        Some(Self { signer, verifier })
36    }
37
38    fn private_key(&self) -> PrivateKey {
39        PrivateKey::from(self.signer.clone())
40    }
41
42    fn public_key(&self) -> PublicKey {
43        PublicKey::from(self.verifier)
44    }
45
46    fn sign(&mut self, namespace: Option<&[u8]>, message: &[u8]) -> Signature {
47        let sig = match namespace {
48            Some(namespace) => self.signer.sign(&union_unique(namespace, message)),
49            None => self.signer.sign(message),
50        };
51        Signature::from(sig)
52    }
53
54    fn verify(
55        namespace: Option<&[u8]>,
56        message: &[u8],
57        public_key: &Self::PublicKey,
58        signature: &Self::Signature,
59    ) -> bool {
60        match namespace {
61            Some(namespace) => {
62                let payload = union_unique(namespace, message);
63                public_key
64                    .key
65                    .verify(&signature.signature, &payload)
66                    .is_ok()
67            }
68            None => public_key.key.verify(&signature.signature, message).is_ok(),
69        }
70    }
71}
72
73/// Ed25519 Batch Verifier.
74pub struct Ed25519Batch {
75    verifier: ed25519_consensus::batch::Verifier,
76}
77
78impl BatchScheme for Ed25519Batch {
79    type PublicKey = PublicKey;
80    type Signature = Signature;
81
82    fn new() -> Self {
83        Ed25519Batch {
84            verifier: ed25519_consensus::batch::Verifier::new(),
85        }
86    }
87
88    fn add(
89        &mut self,
90        namespace: Option<&[u8]>,
91        message: &[u8],
92        public_key: &Self::PublicKey,
93        signature: &Self::Signature,
94    ) -> bool {
95        let payload = match namespace {
96            Some(namespace) => Cow::Owned(union_unique(namespace, message)),
97            None => Cow::Borrowed(message),
98        };
99        let item = ed25519_consensus::batch::Item::from((
100            public_key.key.into(),
101            signature.signature,
102            &payload,
103        ));
104        self.verifier.queue(item);
105        true
106    }
107
108    fn verify<R: RngCore + CryptoRng>(self, rng: &mut R) -> bool {
109        self.verifier.verify(rng).is_ok()
110    }
111}
112
113/// Ed25519 Private Key.
114#[derive(Clone)]
115pub struct PrivateKey {
116    raw: [u8; PRIVATE_KEY_LENGTH],
117    key: ed25519_consensus::SigningKey,
118}
119
120impl Array for PrivateKey {}
121
122impl SizedSerialize for PrivateKey {
123    const SERIALIZED_LEN: usize = PRIVATE_KEY_LENGTH;
124}
125
126impl Eq for PrivateKey {}
127
128impl Hash for PrivateKey {
129    fn hash<H: Hasher>(&self, state: &mut H) {
130        self.raw.hash(state);
131    }
132}
133
134impl PartialEq for PrivateKey {
135    fn eq(&self, other: &Self) -> bool {
136        self.raw == other.raw
137    }
138}
139
140impl Ord for PrivateKey {
141    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
142        self.raw.cmp(&other.raw)
143    }
144}
145
146impl PartialOrd for PrivateKey {
147    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
148        Some(self.cmp(other))
149    }
150}
151
152impl AsRef<[u8]> for PrivateKey {
153    fn as_ref(&self) -> &[u8] {
154        &self.raw
155    }
156}
157
158impl Deref for PrivateKey {
159    type Target = [u8];
160    fn deref(&self) -> &[u8] {
161        &self.raw
162    }
163}
164
165impl From<ed25519_consensus::SigningKey> for PrivateKey {
166    fn from(key: ed25519_consensus::SigningKey) -> Self {
167        let raw = key.to_bytes();
168        Self { raw, key }
169    }
170}
171
172impl TryFrom<&[u8]> for PrivateKey {
173    type Error = Error;
174    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
175        let raw: [u8; PRIVATE_KEY_LENGTH] = value
176            .try_into()
177            .map_err(|_| Error::InvalidPrivateKeyLength)?;
178        let key = ed25519_consensus::SigningKey::from(raw);
179        Ok(Self { raw, key })
180    }
181}
182
183impl TryFrom<&Vec<u8>> for PrivateKey {
184    type Error = Error;
185    fn try_from(value: &Vec<u8>) -> Result<Self, Self::Error> {
186        Self::try_from(value.as_slice())
187    }
188}
189
190impl TryFrom<Vec<u8>> for PrivateKey {
191    type Error = Error;
192    fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
193        Self::try_from(value.as_slice())
194    }
195}
196
197impl Debug for PrivateKey {
198    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
199        write!(f, "{}", hex(&self.raw))
200    }
201}
202
203impl Display for PrivateKey {
204    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
205        write!(f, "{}", hex(&self.raw))
206    }
207}
208
209/// Ed25519 Public Key.
210#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
211pub struct PublicKey {
212    raw: [u8; PUBLIC_KEY_LENGTH],
213    key: ed25519_consensus::VerificationKey,
214}
215
216impl Array for PublicKey {}
217
218impl SizedSerialize for PublicKey {
219    const SERIALIZED_LEN: usize = PUBLIC_KEY_LENGTH;
220}
221
222impl AsRef<[u8]> for PublicKey {
223    fn as_ref(&self) -> &[u8] {
224        &self.raw
225    }
226}
227
228impl Deref for PublicKey {
229    type Target = [u8];
230    fn deref(&self) -> &[u8] {
231        &self.raw
232    }
233}
234
235impl From<VerificationKey> for PublicKey {
236    fn from(key: VerificationKey) -> Self {
237        let raw = key.to_bytes();
238        Self { raw, key }
239    }
240}
241
242impl TryFrom<&[u8]> for PublicKey {
243    type Error = Error;
244    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
245        let raw: [u8; PUBLIC_KEY_LENGTH] = value
246            .try_into()
247            .map_err(|_| Error::InvalidPublicKeyLength)?;
248        let key = VerificationKey::try_from(value).map_err(|_| Error::InvalidPublicKey)?;
249        Ok(Self { raw, key })
250    }
251}
252
253impl TryFrom<&Vec<u8>> for PublicKey {
254    type Error = Error;
255    fn try_from(value: &Vec<u8>) -> Result<Self, Self::Error> {
256        Self::try_from(value.as_slice())
257    }
258}
259
260impl TryFrom<Vec<u8>> for PublicKey {
261    type Error = Error;
262    fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
263        Self::try_from(value.as_slice())
264    }
265}
266
267impl Debug for PublicKey {
268    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
269        write!(f, "{}", hex(&self.raw))
270    }
271}
272
273impl Display for PublicKey {
274    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
275        write!(f, "{}", hex(&self.raw))
276    }
277}
278
279/// Ed25519 Signature.
280#[derive(Clone, Eq, PartialEq)]
281pub struct Signature {
282    raw: [u8; SIGNATURE_LENGTH],
283    signature: ed25519_consensus::Signature,
284}
285
286impl Array for Signature {}
287
288impl SizedSerialize for Signature {
289    const SERIALIZED_LEN: usize = SIGNATURE_LENGTH;
290}
291
292impl Hash for Signature {
293    fn hash<H: Hasher>(&self, state: &mut H) {
294        self.raw.hash(state);
295    }
296}
297
298impl Ord for Signature {
299    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
300        self.raw.cmp(&other.raw)
301    }
302}
303
304impl PartialOrd for Signature {
305    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
306        Some(self.cmp(other))
307    }
308}
309
310impl AsRef<[u8]> for Signature {
311    fn as_ref(&self) -> &[u8] {
312        &self.raw
313    }
314}
315
316impl Deref for Signature {
317    type Target = [u8];
318    fn deref(&self) -> &[u8] {
319        &self.raw
320    }
321}
322
323impl From<ed25519_consensus::Signature> for Signature {
324    fn from(value: ed25519_consensus::Signature) -> Self {
325        let raw = value.to_bytes();
326        Self {
327            raw,
328            signature: value,
329        }
330    }
331}
332
333impl TryFrom<&[u8]> for Signature {
334    type Error = Error;
335    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
336        let raw: [u8; SIGNATURE_LENGTH] = value
337            .try_into()
338            .map_err(|_| Error::InvalidSignatureLength)?;
339        let signature = ed25519_consensus::Signature::from(raw);
340        Ok(Self { raw, signature })
341    }
342}
343
344impl TryFrom<&Vec<u8>> for Signature {
345    type Error = Error;
346    fn try_from(value: &Vec<u8>) -> Result<Self, Self::Error> {
347        Self::try_from(value.as_slice())
348    }
349}
350
351impl TryFrom<Vec<u8>> for Signature {
352    type Error = Error;
353    fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
354        Self::try_from(value.as_slice())
355    }
356}
357
358impl Debug for Signature {
359    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
360        write!(f, "{}", hex(&self.raw))
361    }
362}
363
364impl Display for Signature {
365    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
366        write!(f, "{}", hex(&self.raw))
367    }
368}
369
370/// Test vectors sourced from https://datatracker.ietf.org/doc/html/rfc8032#section-7.1.
371#[cfg(test)]
372mod tests {
373    use super::*;
374    use rand::rngs::OsRng;
375
376    fn test_sign_and_verify(
377        private_key: PrivateKey,
378        public_key: PublicKey,
379        message: &[u8],
380        signature: Signature,
381    ) {
382        let mut signer = <Ed25519 as Scheme>::from(private_key).unwrap();
383        let computed_signature = signer.sign(None, message);
384        assert_eq!(computed_signature, signature);
385        assert!(Ed25519::verify(
386            None,
387            message,
388            &PublicKey::try_from(public_key.to_vec()).unwrap(),
389            &computed_signature
390        ));
391    }
392
393    fn parse_private_key(private_key: &str) -> PrivateKey {
394        PrivateKey::try_from(commonware_utils::from_hex_formatted(private_key).unwrap()).unwrap()
395    }
396
397    fn parse_public_key(public_key: &str) -> PublicKey {
398        PublicKey::try_from(commonware_utils::from_hex_formatted(public_key).unwrap()).unwrap()
399    }
400
401    fn parse_signature(signature: &str) -> Signature {
402        Signature::try_from(commonware_utils::from_hex_formatted(signature).unwrap()).unwrap()
403    }
404
405    fn vector_1() -> (PrivateKey, PublicKey, Vec<u8>, Signature) {
406        (
407            // secret key
408            parse_private_key(
409                "
410                9d61b19deffd5a60ba844af492ec2cc4
411                4449c5697b326919703bac031cae7f60
412                ",
413            ),
414            // public key
415            parse_public_key(
416                "
417                d75a980182b10ab7d54bfed3c964073a
418                0ee172f3daa62325af021a68f707511a
419                ",
420            ),
421            // message
422            b"".to_vec(),
423            // signature
424            parse_signature(
425                "
426                e5564300c360ac729086e2cc806e828a
427                84877f1eb8e5d974d873e06522490155
428                5fb8821590a33bacc61e39701cf9b46b
429                d25bf5f0595bbe24655141438e7a100b
430                ",
431            ),
432        )
433    }
434
435    fn vector_2() -> (PrivateKey, PublicKey, Vec<u8>, Signature) {
436        (
437            // secret key
438            parse_private_key(
439                "
440                4ccd089b28ff96da9db6c346ec114e0f
441                5b8a319f35aba624da8cf6ed4fb8a6fb
442                ",
443            ),
444            // public key
445            parse_public_key(
446                "
447                3d4017c3e843895a92b70aa74d1b7ebc
448                9c982ccf2ec4968cc0cd55f12af4660c
449                ",
450            ),
451            // message
452            [0x72].to_vec(),
453            // signature
454            parse_signature(
455                "
456                92a009a9f0d4cab8720e820b5f642540
457                a2b27b5416503f8fb3762223ebdb69da
458                085ac1e43e15996e458f3613d0f11d8c
459                387b2eaeb4302aeeb00d291612bb0c00
460                ",
461            ),
462        )
463    }
464
465    #[test]
466    fn rfc8032_test_vector_1() {
467        let (private_key, public_key, message, signature) = vector_1();
468        test_sign_and_verify(private_key, public_key, &message, signature)
469    }
470
471    // sanity check the test infra rejects bad signatures
472    #[test]
473    #[should_panic]
474    fn bad_signature() {
475        let (private_key, public_key, message, _) = vector_1();
476        let mut signer = <Ed25519 as Scheme>::new(&mut OsRng);
477        let bad_signature = signer.sign(None, message.as_ref());
478        test_sign_and_verify(private_key, public_key, &message, bad_signature);
479    }
480
481    // sanity check the test infra rejects non-matching messages
482    #[test]
483    #[should_panic]
484    fn different_message() {
485        let (private_key, public_key, _, signature) = vector_1();
486        let different_message = b"this is a different message".to_vec();
487        test_sign_and_verify(private_key, public_key, &different_message, signature);
488    }
489
490    #[test]
491    fn rfc8032_test_vector_2() {
492        let (private_key, public_key, message, signature) = vector_2();
493        test_sign_and_verify(private_key, public_key, &message, signature)
494    }
495
496    #[test]
497    fn rfc8032_test_vector_3() {
498        let private_key = parse_private_key(
499            "
500            c5aa8df43f9f837bedb7442f31dcb7b1
501            66d38535076f094b85ce3a2e0b4458f7
502            ",
503        );
504        let public_key = parse_public_key(
505            "
506            fc51cd8e6218a1a38da47ed00230f058
507            0816ed13ba3303ac5deb911548908025
508            ",
509        );
510        let message: [u8; 2] = [0xaf, 0x82];
511        let signature = parse_signature(
512            "
513            6291d657deec24024827e69c3abe01a3
514            0ce548a284743a445e3680d7db5ac3ac
515            18ff9b538d16f290ae67f760984dc659
516            4a7c15e9716ed28dc027beceea1ec40a
517            ",
518        );
519        test_sign_and_verify(private_key, public_key, &message, signature)
520    }
521
522    #[test]
523    fn rfc8032_test_vector_1024() {
524        let private_key = parse_private_key(
525            "
526            f5e5767cf153319517630f226876b86c
527            8160cc583bc013744c6bf255f5cc0ee5
528            ",
529        );
530        let public_key = parse_public_key(
531            "
532            278117fc144c72340f67d0f2316e8386
533            ceffbf2b2428c9c51fef7c597f1d426e
534            ",
535        );
536        let message = commonware_utils::from_hex_formatted(
537            "
538            08b8b2b733424243760fe426a4b54908
539            632110a66c2f6591eabd3345e3e4eb98
540            fa6e264bf09efe12ee50f8f54e9f77b1
541            e355f6c50544e23fb1433ddf73be84d8
542            79de7c0046dc4996d9e773f4bc9efe57
543            38829adb26c81b37c93a1b270b20329d
544            658675fc6ea534e0810a4432826bf58c
545            941efb65d57a338bbd2e26640f89ffbc
546            1a858efcb8550ee3a5e1998bd177e93a
547            7363c344fe6b199ee5d02e82d522c4fe
548            ba15452f80288a821a579116ec6dad2b
549            3b310da903401aa62100ab5d1a36553e
550            06203b33890cc9b832f79ef80560ccb9
551            a39ce767967ed628c6ad573cb116dbef
552            efd75499da96bd68a8a97b928a8bbc10
553            3b6621fcde2beca1231d206be6cd9ec7
554            aff6f6c94fcd7204ed3455c68c83f4a4
555            1da4af2b74ef5c53f1d8ac70bdcb7ed1
556            85ce81bd84359d44254d95629e9855a9
557            4a7c1958d1f8ada5d0532ed8a5aa3fb2
558            d17ba70eb6248e594e1a2297acbbb39d
559            502f1a8c6eb6f1ce22b3de1a1f40cc24
560            554119a831a9aad6079cad88425de6bd
561            e1a9187ebb6092cf67bf2b13fd65f270
562            88d78b7e883c8759d2c4f5c65adb7553
563            878ad575f9fad878e80a0c9ba63bcbcc
564            2732e69485bbc9c90bfbd62481d9089b
565            eccf80cfe2df16a2cf65bd92dd597b07
566            07e0917af48bbb75fed413d238f5555a
567            7a569d80c3414a8d0859dc65a46128ba
568            b27af87a71314f318c782b23ebfe808b
569            82b0ce26401d2e22f04d83d1255dc51a
570            ddd3b75a2b1ae0784504df543af8969b
571            e3ea7082ff7fc9888c144da2af58429e
572            c96031dbcad3dad9af0dcbaaaf268cb8
573            fcffead94f3c7ca495e056a9b47acdb7
574            51fb73e666c6c655ade8297297d07ad1
575            ba5e43f1bca32301651339e22904cc8c
576            42f58c30c04aafdb038dda0847dd988d
577            cda6f3bfd15c4b4c4525004aa06eeff8
578            ca61783aacec57fb3d1f92b0fe2fd1a8
579            5f6724517b65e614ad6808d6f6ee34df
580            f7310fdc82aebfd904b01e1dc54b2927
581            094b2db68d6f903b68401adebf5a7e08
582            d78ff4ef5d63653a65040cf9bfd4aca7
583            984a74d37145986780fc0b16ac451649
584            de6188a7dbdf191f64b5fc5e2ab47b57
585            f7f7276cd419c17a3ca8e1b939ae49e4
586            88acba6b965610b5480109c8b17b80e1
587            b7b750dfc7598d5d5011fd2dcc5600a3
588            2ef5b52a1ecc820e308aa342721aac09
589            43bf6686b64b2579376504ccc493d97e
590            6aed3fb0f9cd71a43dd497f01f17c0e2
591            cb3797aa2a2f256656168e6c496afc5f
592            b93246f6b1116398a346f1a641f3b041
593            e989f7914f90cc2c7fff357876e506b5
594            0d334ba77c225bc307ba537152f3f161
595            0e4eafe595f6d9d90d11faa933a15ef1
596            369546868a7f3a45a96768d40fd9d034
597            12c091c6315cf4fde7cb68606937380d
598            b2eaaa707b4c4185c32eddcdd306705e
599            4dc1ffc872eeee475a64dfac86aba41c
600            0618983f8741c5ef68d3a101e8a3b8ca
601            c60c905c15fc910840b94c00a0b9d0
602            ",
603        )
604        .unwrap();
605        let signature = parse_signature(
606            "
607            0aab4c900501b3e24d7cdf4663326a3a
608            87df5e4843b2cbdb67cbf6e460fec350
609            aa5371b1508f9f4528ecea23c436d94b
610            5e8fcd4f681e30a6ac00a9704a188a03
611            ",
612        );
613        test_sign_and_verify(private_key, public_key, &message, signature)
614    }
615
616    #[test]
617    fn rfc8032_test_vector_sha() {
618        let private_key = commonware_utils::from_hex_formatted(
619            "
620            833fe62409237b9d62ec77587520911e
621            9a759cec1d19755b7da901b96dca3d42
622            ",
623        )
624        .unwrap();
625        let public_key = commonware_utils::from_hex_formatted(
626            "
627            ec172b93ad5e563bf4932c70e1245034
628            c35467ef2efd4d64ebf819683467e2bf
629            ",
630        )
631        .unwrap();
632        let message = commonware_utils::from_hex_formatted(
633            "
634            ddaf35a193617abacc417349ae204131
635            12e6fa4e89a97ea20a9eeee64b55d39a
636            2192992a274fc1a836ba3c23a3feebbd
637            454d4423643ce80e2a9ac94fa54ca49f
638            ",
639        )
640        .unwrap();
641        let signature = commonware_utils::from_hex_formatted(
642            "
643            dc2a4459e7369633a52b1bf277839a00
644            201009a3efbf3ecb69bea2186c26b589
645            09351fc9ac90b3ecfdfbc7c66431e030
646            3dca179c138ac17ad9bef1177331a704
647            ",
648        )
649        .unwrap();
650        test_sign_and_verify(
651            PrivateKey::try_from(private_key).unwrap(),
652            PublicKey::try_from(public_key).unwrap(),
653            &message,
654            Signature::try_from(signature).unwrap(),
655        )
656    }
657
658    #[test]
659    fn batch_verify_valid() {
660        let v1 = vector_1();
661        let v2 = vector_2();
662        let mut batch = Ed25519Batch::new();
663        assert!(batch.add(None, &v1.2, &v1.1, &v1.3));
664        assert!(batch.add(None, &v2.2, &v2.1, &v2.3));
665        assert!(batch.verify(&mut rand::thread_rng()));
666    }
667
668    #[test]
669    fn batch_verify_invalid() {
670        let v1 = vector_1();
671        let v2 = vector_2();
672        let mut bad_signature = v2.3.to_vec();
673        bad_signature[3] = 0xff;
674
675        let mut batch = Ed25519Batch::new();
676        assert!(batch.add(None, &v1.2, &v1.1, &v1.3));
677        assert!(batch.add(
678            None,
679            &v2.2,
680            &v2.1,
681            &Signature::try_from(bad_signature).unwrap()
682        ));
683        assert!(!batch.verify(&mut rand::thread_rng()));
684    }
685}