dup_crypto/keys/
ed25519.rs

1//  Copyright (C) 2020 Éloïs SANCHEZ.
2//
3// This program is free software: you can redistribute it and/or modify
4// it under the terms of the GNU Affero General Public License as
5// published by the Free Software Foundation, either version 3 of the
6// License, or (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11// GNU Affero General Public License for more details.
12//
13// You should have received a copy of the GNU Affero General Public License
14// along with this program.  If not, see <https://www.gnu.org/licenses/>.
15
16//! Provide wrappers around ed25519 keys and signatures
17//!
18//! Key pairs can be generated with [`KeyPairGenerator`].
19//!
20//! [`KeyPairGenerator`]: struct.KeyPairGenerator.html
21
22#[cfg(feature = "bip32-ed25519")]
23pub mod bip32;
24
25use super::PublicKey as _;
26use super::{PubKeyFromBytesError, SigError};
27use crate::bases::b58::{bytes_to_str_base58, ToBase58};
28use crate::bases::*;
29use crate::hashs::Hash as Hash32;
30use crate::hashs::Hash64;
31use crate::rand::UnspecifiedRandError;
32use crate::scrypt::{params::ScryptParams, scrypt};
33use crate::seeds::Seed32;
34#[cfg(not(target_arch = "wasm32"))]
35use ring::signature::{Ed25519KeyPair as RingKeyPair, KeyPair, UnparsedPublicKey, ED25519};
36use serde::{
37    de::{Deserializer, Error, SeqAccess, Visitor},
38    ser::{SerializeTuple, Serializer},
39    Deserialize, Serialize,
40};
41use std::marker::PhantomData;
42use std::{
43    cmp::Ordering,
44    convert::TryFrom,
45    fmt::{self, Debug, Display, Formatter},
46    hash::Hash,
47    hint::unreachable_unchecked,
48};
49use zeroize::Zeroize;
50
51/// Size of a public key in bytes
52pub const PUBKEY_SIZE_IN_BYTES: usize = 33;
53pub(crate) const PUBKEY_DATAS_SIZE_IN_BYTES: usize = 32;
54/// constf a signature in bytes
55pub const SIG_SIZE_IN_BYTES: usize = 64;
56
57/// Store a ed25519 signature.
58#[derive(Clone, Copy, Eq, Hash, PartialEq)]
59pub struct Signature(pub [u8; 64]);
60
61impl Default for Signature {
62    fn default() -> Self {
63        Signature([0u8; 64])
64    }
65}
66
67impl Serialize for Signature {
68    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
69    where
70        S: Serializer,
71    {
72        let mut seq = serializer.serialize_tuple(self.0.len())?;
73        for elem in &self.0[..] {
74            seq.serialize_element(elem)?;
75        }
76        seq.end()
77    }
78}
79
80#[cfg(not(tarpaulin_include))]
81impl<'de> Deserialize<'de> for Signature {
82    fn deserialize<D>(deserializer: D) -> Result<Signature, D::Error>
83    where
84        D: Deserializer<'de>,
85    {
86        struct ArrayVisitor {
87            element: PhantomData<u8>,
88        }
89
90        impl<'de> Visitor<'de> for ArrayVisitor {
91            type Value = Signature;
92
93            #[cfg(not(tarpaulin_include))]
94            fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
95                formatter.write_str(concat!("an array of length ", 64))
96            }
97
98            fn visit_seq<A>(self, mut seq: A) -> Result<Signature, A::Error>
99            where
100                A: SeqAccess<'de>,
101            {
102                let mut arr = [0u8; 64];
103                for (i, byte) in arr.iter_mut().take(64).enumerate() {
104                    *byte = seq
105                        .next_element()?
106                        .ok_or_else(|| Error::invalid_length(i, &self))?;
107                }
108                Ok(Signature(arr))
109            }
110        }
111
112        let visitor: ArrayVisitor = ArrayVisitor {
113            element: PhantomData,
114        };
115        deserializer.deserialize_tuple(64, visitor)
116    }
117}
118
119impl super::Signature for Signature {
120    #[inline]
121    fn from_base64(base64_data: &str) -> Result<Signature, BaseConversionError> {
122        Ok(Signature(b64::str_base64_to64bytes(base64_data)?))
123    }
124
125    fn to_bytes_vector(&self) -> Vec<u8> {
126        self.0.to_vec()
127    }
128
129    fn to_base64(&self) -> String {
130        base64::encode(&self.0[..]) // need to take a slice for required trait `AsRef<[u8]>`
131    }
132}
133
134impl Display for Signature {
135    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
136        use super::Signature;
137
138        write!(f, "{}", self.to_base64())
139    }
140}
141
142impl Debug for Signature {
143    // Signature { 1eubHHb... }
144    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
145        write!(f, "Signature {{ {} }}", self)
146    }
147}
148
149/// Store a Ed25519 public key.
150///
151/// Can be generated with [`KeyPairGenerator`].
152///
153/// [`KeyPairGenerator`]: struct.KeyPairGenerator.html
154#[derive(Copy, Clone, Deserialize, Eq, Hash, PartialEq, Serialize)]
155pub struct PublicKey {
156    pub(crate) datas: [u8; 32],
157    count_leading_zero: u8,
158}
159
160impl Default for PublicKey {
161    fn default() -> Self {
162        PublicKey {
163            datas: [0u8; 32],
164            count_leading_zero: 32,
165        }
166    }
167}
168
169impl AsRef<[u8]> for PublicKey {
170    fn as_ref(&self) -> &[u8] {
171        unsafe { std::slice::from_raw_parts(self.datas.as_ptr(), PUBKEY_SIZE_IN_BYTES) }
172    }
173}
174use thiserror::Error;
175#[derive(Clone, Copy, Debug, Error, PartialEq)]
176/// Error when parse a public key from base 58 representation with optional checksum
177pub enum PublicKeyFromStrErr {
178    /// Base conversion error
179    #[error("{0}")]
180    BaseConversionError(BaseConversionError),
181    /// Empty string
182    #[error("Empty string")]
183    EmptyString,
184    /// Invalid checksum
185    #[error("Invalid checksum")]
186    InvalidChecksum,
187}
188
189impl PublicKey {
190    /// Compute public key checksum
191    pub fn checksum(&self) -> String {
192        let double_hash = Hash32::compute(Hash32::compute(&self.datas[..]).as_ref());
193        let mut checksum = bs58::encode(double_hash).into_string();
194        checksum.truncate(3);
195        checksum
196    }
197    /// Parse public key from base58 representation with optional checksum
198    pub fn from_base58_with_checksum_opt(source: &str) -> Result<Self, PublicKeyFromStrErr> {
199        let mut source = source.split(':');
200        if let Some(b58_str) = source.next() {
201            let pubkey =
202                Self::from_base58(b58_str).map_err(PublicKeyFromStrErr::BaseConversionError)?;
203            if let Some(checksum) = source.next() {
204                if pubkey.checksum() == checksum {
205                    Ok(pubkey)
206                } else {
207                    Err(PublicKeyFromStrErr::InvalidChecksum)
208                }
209            } else {
210                Ok(pubkey)
211            }
212        } else {
213            Err(PublicKeyFromStrErr::EmptyString)
214        }
215    }
216    /// Verify if bytes represents a valid point on the Edwards form of Curve25519.
217    #[cfg(feature = "pubkey_check")]
218    fn check_bytes(bytes: &[u8]) -> bool {
219        curve25519_dalek::edwards::CompressedEdwardsY::from_slice(bytes)
220            .decompress()
221            .is_some()
222    }
223    #[cfg(not(feature = "pubkey_check"))]
224    fn check_bytes(_: &[u8]) -> bool {
225        true
226    }
227    /// WARNING: This function not handle leading 1
228    /// Must not be used to parse user document generated by a non-rust code !
229    #[doc(hidden)]
230    pub fn from_32_bytes_array(data: [u8; 32]) -> Self {
231        PublicKey {
232            datas: data,
233            count_leading_zero: 0,
234        }
235    }
236}
237
238impl TryFrom<&[u8]> for PublicKey {
239    type Error = PubKeyFromBytesError;
240
241    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
242        if bytes.len() > PUBKEY_SIZE_IN_BYTES {
243            Err(PubKeyFromBytesError::InvalidBytesLen {
244                expected: PUBKEY_SIZE_IN_BYTES,
245                found: bytes.len(),
246            })
247        } else {
248            let (count_leading_zero, datas_bytes) = if bytes.len() <= PUBKEY_DATAS_SIZE_IN_BYTES {
249                (0, bytes)
250            } else {
251                (
252                    bytes[PUBKEY_DATAS_SIZE_IN_BYTES],
253                    &bytes[..PUBKEY_DATAS_SIZE_IN_BYTES],
254                )
255            };
256            // Ensure that given bytes represents a valid point on the Edwards form of Curve25519.
257            if Self::check_bytes(datas_bytes) {
258                let mut u8_array = [0; PUBKEY_DATAS_SIZE_IN_BYTES];
259                u8_array[(PUBKEY_DATAS_SIZE_IN_BYTES - datas_bytes.len())..]
260                    .copy_from_slice(datas_bytes);
261
262                Ok(PublicKey {
263                    datas: u8_array,
264                    count_leading_zero,
265                })
266            } else {
267                Err(PubKeyFromBytesError::InvalidBytesContent)
268            }
269        }
270    }
271}
272
273impl ToBase58 for PublicKey {
274    fn to_base58(&self) -> String {
275        bytes_to_str_base58(self.datas.as_ref(), self.count_leading_zero)
276    }
277}
278
279impl Display for PublicKey {
280    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
281        write!(
282            f,
283            "{}",
284            bytes_to_str_base58(self.datas.as_ref(), self.count_leading_zero)
285        )
286    }
287}
288
289impl Debug for PublicKey {
290    // PublicKey { DNann1L... }
291    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
292        write!(f, "PublicKey {{ {} }}", self)
293    }
294}
295
296impl PartialOrd for PublicKey {
297    fn partial_cmp(&self, other: &PublicKey) -> Option<Ordering> {
298        Some(match self.datas.cmp(&other.datas) {
299            Ordering::Equal => self.count_leading_zero.cmp(&other.count_leading_zero),
300            Ordering::Less => Ordering::Less,
301            Ordering::Greater => Ordering::Greater,
302        })
303    }
304}
305impl Ord for PublicKey {
306    fn cmp(&self, other: &Self) -> Ordering {
307        match self.datas.cmp(&other.datas) {
308            Ordering::Equal => self.count_leading_zero.cmp(&other.count_leading_zero),
309            Ordering::Less => Ordering::Less,
310            Ordering::Greater => Ordering::Greater,
311        }
312    }
313}
314
315impl super::PublicKey for PublicKey {
316    type Signature = Signature;
317
318    #[inline]
319    fn from_base58(base58_data: &str) -> Result<Self, BaseConversionError> {
320        let (datas, count_leading_zero) = b58::str_base58_to_32bytes(base58_data)?;
321        Ok(PublicKey {
322            datas,
323            count_leading_zero,
324        })
325    }
326
327    fn to_bytes_vector(&self) -> Vec<u8> {
328        self.as_ref().to_vec()
329    }
330
331    #[cfg(target_arch = "wasm32")]
332    #[cfg(not(tarpaulin_include))]
333    fn verify(&self, message: &[u8], signature: &Self::Signature) -> Result<(), SigError> {
334        if cryptoxide::ed25519::verify(message, self.datas.as_ref(), &signature.0[..]) {
335            Ok(())
336        } else {
337            Err(SigError::InvalidSig)
338        }
339    }
340    #[cfg(not(target_arch = "wasm32"))]
341    fn verify(&self, message: &[u8], signature: &Self::Signature) -> Result<(), SigError> {
342        UnparsedPublicKey::new(&ED25519, self.datas.as_ref())
343            .verify(message, &signature.0)
344            .map_err(|_| SigError::InvalidSig)
345    }
346}
347
348#[cfg(target_arch = "wasm32")]
349#[cfg(not(tarpaulin_include))]
350fn get_cryptoxide_ed25519_pubkey(pubkey_bytes: [u8; 32]) -> PublicKey {
351    PublicKey::try_from(&pubkey_bytes[..]).unwrap_or_else(|_| unsafe { unreachable_unchecked() })
352}
353#[cfg(not(target_arch = "wasm32"))]
354fn get_ring_ed25519_pubkey(ring_key_pair: &RingKeyPair) -> PublicKey {
355    let ring_pubkey: <RingKeyPair as KeyPair>::PublicKey = *ring_key_pair.public_key();
356    PublicKey::try_from(ring_pubkey.as_ref()).unwrap_or_else(|_| unsafe { unreachable_unchecked() })
357}
358
359#[cfg(target_arch = "wasm32")]
360#[cfg(not(tarpaulin_include))]
361/// Store a ed25519 cryptographic signator
362#[allow(missing_copy_implementations)]
363pub struct Signator {
364    public_key: PublicKey,
365    secret_key: [u8; 64],
366}
367#[cfg(target_arch = "wasm32")]
368#[cfg(not(tarpaulin_include))]
369impl Debug for Signator {
370    // Signature { 1eubHHb... }
371    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
372        write!(
373            f,
374            "Signator {{ public_key: {}, secret_key: hidden }}",
375            self.public_key
376        )
377    }
378}
379#[cfg(not(target_arch = "wasm32"))]
380/// Store a ed25519 cryptographic signator
381#[derive(Debug)]
382pub struct Signator(RingKeyPair);
383
384impl super::Signator for Signator {
385    type PublicKey = PublicKey;
386
387    #[cfg(target_arch = "wasm32")]
388    #[cfg(not(tarpaulin_include))]
389    fn public_key(&self) -> Self::PublicKey {
390        self.public_key
391    }
392    #[cfg(not(target_arch = "wasm32"))]
393    fn public_key(&self) -> Self::PublicKey {
394        get_ring_ed25519_pubkey(&self.0)
395    }
396    #[cfg(target_arch = "wasm32")]
397    #[cfg(not(tarpaulin_include))]
398    fn sign(&self, message: &[u8]) -> <Self::PublicKey as super::PublicKey>::Signature {
399        let sig_bytes = cryptoxide::ed25519::signature(message, &self.secret_key[..]);
400        Signature(sig_bytes)
401    }
402    #[cfg(not(target_arch = "wasm32"))]
403    fn sign(&self, message: &[u8]) -> <Self::PublicKey as super::PublicKey>::Signature {
404        let mut sig_bytes = [0u8; 64];
405        sig_bytes.copy_from_slice(self.0.sign(message).as_ref());
406        Signature(sig_bytes)
407    }
408}
409
410/// Store a ed25519 cryptographic key pair (`PublicKey` + `PrivateKey`)
411#[derive(Debug, Clone, Eq)]
412pub struct Ed25519KeyPair {
413    /// Store a Ed25519 public key.
414    pubkey: PublicKey,
415    /// Store a seed of 32 bytes.
416    seed: Seed32,
417}
418
419impl Ed25519KeyPair {
420    /// Generate random keypair
421    pub fn generate_random() -> Result<Self, UnspecifiedRandError> {
422        Ok(KeyPairFromSeed32Generator::generate(Seed32::random()?))
423    }
424    #[allow(dead_code)]
425    pub(crate) fn seed(&self) -> &Seed32 {
426        &self.seed
427    }
428}
429
430impl Display for Ed25519KeyPair {
431    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
432        write!(f, "({}, hidden)", self.pubkey.to_base58())
433    }
434}
435
436impl PartialEq<Ed25519KeyPair> for Ed25519KeyPair {
437    fn eq(&self, other: &Ed25519KeyPair) -> bool {
438        self.pubkey.eq(&other.pubkey) && self.seed.eq(&other.seed)
439    }
440}
441
442impl super::inner::KeyPairInner for Ed25519KeyPair {
443    fn scalar_bytes_without_normalization(&self) -> [u8; 32] {
444        let hash: Hash64 = Hash64::sha512(self.seed.as_ref());
445        //normalize_bytes_ed25519(&mut hash.0);
446
447        let mut scalar_bytes = [0; 32];
448        scalar_bytes.copy_from_slice(&hash.0[..32]);
449        scalar_bytes
450    }
451}
452
453impl super::KeyPair for Ed25519KeyPair {
454    type Seed = Seed32;
455    type Signator = Signator;
456
457    #[cfg(target_arch = "wasm32")]
458    #[cfg(not(tarpaulin_include))]
459    fn generate_signator(&self) -> Self::Signator {
460        let (secret_key, public_key) = cryptoxide::ed25519::keypair(self.seed.as_ref());
461        Signator {
462            public_key: get_cryptoxide_ed25519_pubkey(public_key),
463            secret_key,
464        }
465    }
466    #[cfg(not(target_arch = "wasm32"))]
467    fn generate_signator(&self) -> Self::Signator {
468        Signator(
469            RingKeyPair::from_seed_unchecked(self.seed.as_ref())
470                .unwrap_or_else(|_| unsafe { unreachable_unchecked() }),
471        )
472    }
473
474    fn from_seed(seed: Self::Seed) -> Self {
475        KeyPairFromSeed32Generator::generate(seed)
476    }
477
478    fn public_key(&self) -> PublicKey {
479        self.pubkey
480    }
481
482    fn verify(
483        &self,
484        message: &[u8],
485        signature: &<<Self::Signator as super::Signator>::PublicKey as super::PublicKey>::Signature,
486    ) -> Result<(), SigError> {
487        self.public_key().verify(message, signature)
488    }
489
490    fn upcast(self) -> super::KeyPairEnum {
491        super::KeyPairEnum::Ed25519(self)
492    }
493}
494
495/// Keypair generator with seed
496#[derive(Debug, Copy, Clone)]
497pub struct KeyPairFromSeed32Generator {}
498
499impl KeyPairFromSeed32Generator {
500    #[cfg(target_arch = "wasm32")]
501    #[cfg(not(tarpaulin_include))]
502    /// Create a keypair based on a given seed.
503    ///
504    /// The [`PublicKey`](struct.PublicKey.html) will be able to verify messaged signed with
505    /// the [`PrivateKey`](struct.PrivateKey.html).
506    pub fn generate(seed: Seed32) -> Ed25519KeyPair {
507        Ed25519KeyPair {
508            pubkey: get_cryptoxide_ed25519_pubkey(cryptoxide::ed25519::keypair(seed.as_ref()).1),
509            seed,
510        }
511    }
512    #[cfg(not(target_arch = "wasm32"))]
513    /// Create a keypair based on a given seed.
514    ///
515    /// The [`PublicKey`](struct.PublicKey.html) will be able to verify messaged signed with
516    /// the [`PrivateKey`](struct.PrivateKey.html).
517    pub fn generate(seed: Seed32) -> Ed25519KeyPair {
518        let ring_key_pair = RingKeyPair::from_seed_unchecked(seed.as_ref())
519            .unwrap_or_else(|_| unsafe { unreachable_unchecked() });
520        Ed25519KeyPair {
521            pubkey: get_ring_ed25519_pubkey(&ring_key_pair),
522            seed,
523        }
524    }
525}
526
527#[derive(Zeroize)]
528#[zeroize(drop)]
529/// Salted password
530pub struct SaltedPassword {
531    salt: String,
532    password: String,
533}
534
535impl SaltedPassword {
536    /// Create new salted password
537    pub fn new(salt: String, password: String) -> SaltedPassword {
538        SaltedPassword { salt, password }
539    }
540}
541/// Keypair generator with given parameters for `scrypt` keypair function.
542#[derive(Copy, Clone)]
543pub struct KeyPairFromSaltedPasswordGenerator {
544    scrypt_params: ScryptParams,
545}
546
547impl KeyPairFromSaltedPasswordGenerator {
548    /// Create a `KeyPairGenerator` with default arguments `(log_n: 12, r: 16, p: 1)`
549    pub fn with_default_parameters() -> KeyPairFromSaltedPasswordGenerator {
550        KeyPairFromSaltedPasswordGenerator {
551            scrypt_params: ScryptParams::default(),
552        }
553    }
554
555    /// Create a `KeyPairFromSaltedPasswordGenerator` with given arguments.
556    ///
557    /// # Arguments
558    ///
559    /// - log_n - The log2 of the Scrypt parameter N
560    /// - r - The Scrypt parameter r
561    /// - p - The Scrypt parameter p
562    pub fn with_parameters(log_n: u8, r: u32, p: u32) -> KeyPairFromSaltedPasswordGenerator {
563        KeyPairFromSaltedPasswordGenerator {
564            scrypt_params: ScryptParams::new(log_n, r, p),
565        }
566    }
567
568    /// Create a seed based on a given password and salt.
569    pub fn generate_seed(&self, password: &[u8], salt: &[u8]) -> Seed32 {
570        let mut seed = [0u8; 32];
571
572        scrypt(password, salt, &self.scrypt_params, &mut seed);
573
574        Seed32::new(seed)
575    }
576
577    /// Create a keypair based on a given password and salt.
578    ///
579    /// The [`PublicKey`](struct.PublicKey.html) will be able to verify messaged signed with
580    /// the [`PrivateKey`](struct.PrivateKey.html).
581    pub fn generate(&self, salted_password: SaltedPassword) -> Ed25519KeyPair {
582        // Generate seed from tuple (password + salt)
583        let seed = self.generate_seed(
584            salted_password.password.as_bytes(),
585            salted_password.salt.as_bytes(),
586        );
587        // Generate keypair from seed
588        KeyPairFromSeed32Generator::generate(seed)
589    }
590}
591
592/*fn normalize_bytes_ed25519(bytes: &mut [u8; EXTENDED_SECRET_KEY_SIZE]) {
593    bytes[0] &= 248;
594    bytes[31] &= 63;
595    bytes[31] |= 64;
596}*/
597
598#[cfg(test)]
599mod tests {
600    use super::*;
601    use crate::keys::{KeyPair, Sig, Signator, Signature};
602    use crate::seeds::Seed32;
603    use std::{collections::hash_map::DefaultHasher, hash::Hasher};
604    use unwrap::unwrap;
605
606    #[test]
607    fn base58_seed() {
608        let seed58 = "DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV";
609
610        // Test base58 encoding/decoding (loop for every bytes)
611        let seed = unwrap!(Seed32::from_base58(seed58));
612        assert_eq!(seed.to_base58(), seed58);
613
614        // Test seed display and debug
615        assert_eq!(
616            "DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV".to_owned(),
617            format!("{}", seed)
618        );
619        assert_eq!(
620            "Seed32 { DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV }".to_owned(),
621            format!("{:?}", seed)
622        );
623
624        // Test seed equality
625        let same_seed = seed.clone();
626        let other_seed = Seed32::default();
627        assert!(seed.eq(&same_seed));
628        assert!(!seed.eq(&other_seed));
629
630        // Test seed parsing
631        assert_eq!(
632            Seed32::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQd<<").unwrap_err(),
633            BaseConversionError::InvalidCharacter {
634                character: '<',
635                offset: 42
636            }
637        );
638    }
639
640    #[test]
641    fn test_pubkey_111_from_base58() -> Result<(), bincode::Error> {
642        let public58 = "11111111111111111111111111111111111111111111";
643        let public_key = unwrap!(super::PublicKey::from_base58(public58));
644        assert_eq!(
645            &[
646                0u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
647                0, 0, 0, 0, 0, 44
648            ][..],
649            public_key.as_ref(),
650        );
651        assert_eq!(
652            bincode::serialize(&public_key)?,
653            public_key.to_bytes_vector(),
654        );
655        Ok(())
656    }
657
658    #[test]
659    fn test_pubkey_with_leading_1() -> Result<(), bincode::Error> {
660        let public58 = "13fn6X3XWVgshHTgS8beZMo9XiyScx6MB6yPsBB5ZBia";
661        let public_key = unwrap!(super::PublicKey::from_base58(public58));
662        assert_eq!(
663            bincode::serialize(&public_key)?,
664            public_key.to_bytes_vector(),
665        );
666        assert_eq!(&public_key.to_string(), public58);
667        Ok(())
668    }
669
670    #[test]
671    fn test_other_pubkey_with_leading_1() -> Result<(), bincode::Error> {
672        let public58 = "1V27SH9TiVEDs8TWFPydpRKxhvZari7wjGwQnPxMnkr";
673        let public_key = unwrap!(super::PublicKey::from_base58(public58));
674        assert_eq!(
675            bincode::serialize(&public_key)?,
676            public_key.to_bytes_vector(),
677        );
678        assert_eq!(&public_key.to_string(), public58);
679        Ok(())
680    }
681
682    #[test]
683    fn test_third_pubkey_with_leading_1() -> Result<(), bincode::Error> {
684        let public58 = "1XoFs76G4yidvVY3FZBwYyLXTMjabryhFD8mNQPkQKHk";
685        let public_key = unwrap!(super::PublicKey::from_base58(public58));
686        assert_eq!(
687            bincode::serialize(&public_key)?,
688            public_key.to_bytes_vector(),
689        );
690        println!("public_key_with_leading_1={:?}", public_key.as_ref());
691        println!("public_key_with_leading_1={}", public_key);
692        let public_key_without_leading_1 = unwrap!(super::PublicKey::from_base58(
693            "XoFs76G4yidvVY3FZBwYyLXTMjabryhFD8mNQPkQKHk"
694        ));
695        println!(
696            "public_key_without_leading_1={:?}",
697            public_key_without_leading_1.as_ref()
698        );
699        println!(
700            "public_key_without_leading_1={}",
701            public_key_without_leading_1
702        );
703        assert_eq!(&public_key.to_string(), public58);
704        Ok(())
705    }
706
707    #[test]
708    fn base58_public_key() -> Result<(), bincode::Error> {
709        let public58 = "DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV";
710        let public_key = unwrap!(super::PublicKey::from_base58(public58));
711
712        // Test base58 encoding/decoding (loop for every bytes)
713        assert_eq!(public_key.to_base58(), public58);
714        let public_raw = unwrap!(b58::str_base58_to_32bytes(public58));
715        assert_eq!(
716            public_raw.0.to_vec(),
717            &public_key.to_bytes_vector()[..PUBKEY_DATAS_SIZE_IN_BYTES]
718        );
719        for (key, raw) in public_key.datas.as_ref().iter().zip(public_raw.0.iter()) {
720            assert_eq!(key, raw);
721        }
722
723        // Test binary encoding/decoding
724        assert_eq!(
725            bincode::serialize(&public_key)?,
726            public_key.to_bytes_vector(),
727        );
728
729        // Test pubkey debug
730        assert_eq!(
731            "PublicKey { DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV }".to_owned(),
732            format!("{:?}", public_key)
733        );
734
735        // Test pubkey with 43 characters
736        let pubkey43 = unwrap!(super::PublicKey::from_base58(
737            "2nV7Dv4nhTJ9dZUvRJpL34vFP9b2BkDjKWv9iBW2JaR"
738        ));
739        println!("pubkey43={:?}", pubkey43.as_ref());
740        assert_eq!(
741            format!("{:?}", pubkey43),
742            "PublicKey { 2nV7Dv4nhTJ9dZUvRJpL34vFP9b2BkDjKWv9iBW2JaR }".to_owned(),
743        );
744        assert_eq!(
745            super::PublicKey::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQd<<")
746                .unwrap_err(),
747            BaseConversionError::InvalidCharacter {
748                character: '<',
749                offset: 42
750            }
751        );
752        Ok(())
753    }
754
755    #[test]
756    fn base64_signature() {
757        let signature64 = "1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FG\
758                           MMmQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg==";
759        let signature = unwrap!(super::Signature::from_base64(signature64));
760
761        // Test signature base64 encoding/decoding (loop for every bytes)
762        assert_eq!(signature.to_base64(), signature64);
763        let signature_raw = unwrap!(base64::decode(signature64));
764        for (sig, raw) in signature.0.iter().zip(signature_raw.iter()) {
765            assert_eq!(sig, raw);
766        }
767
768        // Test signature display and debug
769        assert_eq!(
770            "1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FGMMmQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg==".to_owned(),
771            format!("{}", signature)
772        );
773        assert_eq!(
774            "Signature { 1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FGMMmQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg== }".to_owned(),
775            format!("{:?}", signature)
776        );
777
778        // Test signature hash
779        let mut hasher = DefaultHasher::new();
780        signature.hash(&mut hasher);
781        let hash1 = hasher.finish();
782        let mut hasher = DefaultHasher::new();
783        let signature_copy = signature;
784        signature_copy.hash(&mut hasher);
785        let hash2 = hasher.finish();
786        assert_eq!(hash1, hash2);
787
788        // Test signature serialization/deserialization
789        let mut bin_sig = unwrap!(bincode::serialize(&signature));
790        assert_eq!(SIG_SIZE_IN_BYTES, bin_sig.len());
791        assert_eq!(signature.to_bytes_vector(), bin_sig);
792        assert_eq!(signature, unwrap!(bincode::deserialize(&bin_sig)),);
793        bin_sig.push(0); // add on byte to simulate invalid length
794        bincode::deserialize::<Sig>(&bin_sig)
795            .expect_err("Deserialization must be fail because length is invalid !");
796
797        // Test signature parsing
798        assert_eq!(
799            super::Signature::from_base64("YmhlaW9iaHNlcGlvaGVvaXNlcGl2ZXBvdm5pc2U=").unwrap_err(),
800            BaseConversionError::InvalidBaseConverterLength
801        );
802        assert_eq!(
803            super::Signature::from_base64(
804                "YmhlaW9iaHNlcGlvaGVvaXNlcGl2ZXBvdm5pc2V2c2JlaW9idmVpb3Zqc\
805                 2V2Z3BpaHNlamVwZ25qZXNqb2dwZWpnaW9zZXNkdnNic3JicmJyZGJyZGI=",
806            )
807            .unwrap_err(),
808            BaseConversionError::InvalidBaseConverterLength
809        );
810        assert_eq!(
811            super::Signature::from_base64(
812                "ziv50X9Ch7rWiN87BG0QWzjHu/VKqJVYStC3G4pd8ck8jT0XAeN0mMxZ5LE2IRs/B81L7GsQWjKA/eiTocsCAw<<",
813            )
814            .unwrap_err(),
815            BaseConversionError::InvalidCharacter {
816                character: '<',
817                offset: 86
818            }
819        );
820        assert_eq!(
821            super::Signature::from_base64(
822                "1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FG\
823                 MMmQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg===",
824            )
825            .unwrap_err(),
826            BaseConversionError::InvalidBaseConverterLength,
827        );
828    }
829
830    #[test]
831    fn message_sign_verify() {
832        let seed = unwrap!(Seed32::from_base58(
833            "DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV"
834        ));
835
836        let expected_signature = unwrap!(super::Signature::from_base64(
837            "9ARKYkEAwp+kQ01rgvWUwJLchVLpZvHg3t/3H32XwWOoG119NiVCtfPSPtR4GDOeOz6Y+29drOLahqhzy+ciBw==",
838        ));
839
840        let message = "Version: 10
841Type: Identity
842Currency: duniter_unit_test_currency
843Issuer: DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV
844UniqueID: tic
845Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
846";
847
848        let signator = KeyPairFromSeed32Generator::generate(seed).generate_signator();
849        let pubkey = signator.public_key();
850        let sig = signator.sign(message.as_bytes());
851        let wrong_sig = Signature([
852            0u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
853            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
854            0, 0, 0, 0, 0, 0, 0,
855        ]);
856
857        assert_eq!(sig, expected_signature);
858        assert_eq!(Ok(()), pubkey.verify(message.as_bytes(), &sig));
859        assert_eq!(
860            Err(SigError::InvalidSig),
861            pubkey.verify(message.as_bytes(), &wrong_sig)
862        );
863    }
864
865    #[test]
866    fn keypair_generate() {
867        let key_pair1 = KeyPairFromSaltedPasswordGenerator::with_default_parameters().generate(
868            SaltedPassword::new(
869                "JhxtHB7UcsDbA9wMSyMKXUzBZUQvqVyB32KwzS9SWoLkjrUhHV".to_owned(),
870                "JhxtHB7UcsDbA9wMSyMKXUzBZUQvqVyB32KwzS9SWoLkjrUhHV_".to_owned(),
871            ),
872        );
873
874        assert_eq!(
875            key_pair1.pubkey.to_string(),
876            "7iMV3b6j2hSj5WtrfchfvxivS9swN3opDgxudeHq64fb"
877        );
878
879        let key_pair2 = KeyPairFromSaltedPasswordGenerator::with_parameters(12u8, 16, 1)
880            .generate(SaltedPassword::new("toto".to_owned(), "toto".to_owned()));
881
882        // Test signature display and debug
883        assert_eq!(
884            "(EA7Dsw39ShZg4SpURsrgMaMqrweJPUFPYHwZA8e92e3D, hidden)".to_owned(),
885            format!("{}", key_pair2)
886        );
887
888        // Test key_pair equality
889        let same_key_pair = key_pair2.clone();
890        let other_key_pair = KeyPairFromSeed32Generator::generate(Seed32::new([
891            0u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
892            0, 0, 0, 0,
893        ]));
894        assert!(key_pair2.eq(&same_key_pair));
895        assert!(!key_pair2.eq(&other_key_pair));
896    }
897
898    #[test]
899    fn keypair_generate_sign_and_verify() {
900        let keypair = KeyPairFromSaltedPasswordGenerator::with_default_parameters().generate(
901            SaltedPassword::new("password".to_owned(), "salt".to_owned()),
902        );
903
904        let message = "Version: 10
905Type: Identity
906Currency: duniter_unit_test_currency
907Issuer: DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV
908UniqueID: tic
909Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
910";
911
912        let sig = keypair.generate_signator().sign(message.as_bytes());
913        assert!(keypair.verify(message.as_bytes(), &sig).is_ok());
914    }
915
916    #[test]
917    #[cfg(feature = "pubkey_check")]
918    fn invalid_pubkey() {
919        let invalid_bytes = [
920            206u8, 58, 67, 221, 20, 133, 0, 225, 86, 115, 26, 104, 142, 116, 140, 132, 119, 51,
921            175, 45, 82, 225, 14, 195, 7, 107, 43, 212, 8, 37, 234, 23,
922        ];
923
924        if let Err(PubKeyFromBytesError::InvalidBytesContent) =
925            PublicKey::try_from(&invalid_bytes[..])
926        {
927        } else {
928            panic!("expected PubKeyFromBytesError::InvalidBytesContent");
929        }
930    }
931
932    #[test]
933    fn test_parse_expanded_base58_private_key() {
934        let bytes = unwrap!(bs58::decode(
935            "31uSnvigJtJEUgG4YDqJB99awp4hkYgYqb3Yzu8P1LP5ZPMHtwNoCohVhm6jKcG9HFHbagDWdcoPgYBgHhdg5Efo"
936        ).into_vec());
937        let mut seed = [0u8; 32];
938        seed.copy_from_slice(&bytes[..32]);
939        let mut pubkey_bytes = [0u8; 32];
940        pubkey_bytes.copy_from_slice(&bytes[32..64]);
941
942        let keypair = KeyPairFromSeed32Generator::generate(Seed32::new(seed));
943        println!("seed={}", keypair.seed());
944        assert_eq!(
945            "8hgzaeFnjkNCsemcaL4rmhB2999B79BydtE8xow4etB7",
946            &keypair.public_key().to_base58()
947        );
948        assert_eq!(
949            "8hgzaeFnjkNCsemcaL4rmhB2999B79BydtE8xow4etB7",
950            &bs58::encode(&pubkey_bytes).into_string(),
951        );
952    }
953
954    #[test]
955    fn test_checksum() {
956        // RFC example 1
957        let pubkey1: PublicKey = unwrap!(PublicKey::from_base58(
958            "2BjyvjoAf5qik7R8TKDJAHJugsX23YgJGi2LmBUv2nx"
959        ));
960        assert_eq!(&pubkey1.checksum(), "8pQ");
961        assert!(PublicKey::from_base58_with_checksum_opt(
962            "2BjyvjoAf5qik7R8TKDJAHJugsX23YgJGi2LmBUv2nx:8pQ"
963        )
964        .is_ok());
965        assert_eq!(
966            PublicKey::from_base58_with_checksum_opt(
967                "2BjyvjoAf5qik7R8TKDJAHJugsX23YgJGi2LmBUv2nx:8pq"
968            ),
969            Err(PublicKeyFromStrErr::InvalidChecksum)
970        );
971
972        // RFC example 2
973        let pubkey2: PublicKey = unwrap!(PublicKey::from_base58(
974            "J4c8CARmP9vAFNGtHRuzx14zvxojyRWHW2darguVqjtX"
975        ));
976        assert_eq!(&pubkey2.checksum(), "KAv");
977        assert!(PublicKey::from_base58_with_checksum_opt(
978            "J4c8CARmP9vAFNGtHRuzx14zvxojyRWHW2darguVqjtX:KAv"
979        )
980        .is_ok());
981        assert_eq!(
982            PublicKey::from_base58_with_checksum_opt(
983                "J4c8CARmP9vAFNGtHRuzx14zvxojyRWHW2darguVqjtX:kAv"
984            ),
985            Err(PublicKeyFromStrErr::InvalidChecksum)
986        );
987    }
988}