1#[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
51pub const PUBKEY_SIZE_IN_BYTES: usize = 33;
53pub(crate) const PUBKEY_DATAS_SIZE_IN_BYTES: usize = 32;
54pub const SIG_SIZE_IN_BYTES: usize = 64;
56
57#[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[..]) }
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 fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
145 write!(f, "Signature {{ {} }}", self)
146 }
147}
148
149#[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)]
176pub enum PublicKeyFromStrErr {
178 #[error("{0}")]
180 BaseConversionError(BaseConversionError),
181 #[error("Empty string")]
183 EmptyString,
184 #[error("Invalid checksum")]
186 InvalidChecksum,
187}
188
189impl PublicKey {
190 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 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 #[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 #[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 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 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#[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 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#[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#[derive(Debug, Clone, Eq)]
412pub struct Ed25519KeyPair {
413 pubkey: PublicKey,
415 seed: Seed32,
417}
418
419impl Ed25519KeyPair {
420 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 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#[derive(Debug, Copy, Clone)]
497pub struct KeyPairFromSeed32Generator {}
498
499impl KeyPairFromSeed32Generator {
500 #[cfg(target_arch = "wasm32")]
501 #[cfg(not(tarpaulin_include))]
502 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 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)]
529pub struct SaltedPassword {
531 salt: String,
532 password: String,
533}
534
535impl SaltedPassword {
536 pub fn new(salt: String, password: String) -> SaltedPassword {
538 SaltedPassword { salt, password }
539 }
540}
541#[derive(Copy, Clone)]
543pub struct KeyPairFromSaltedPasswordGenerator {
544 scrypt_params: ScryptParams,
545}
546
547impl KeyPairFromSaltedPasswordGenerator {
548 pub fn with_default_parameters() -> KeyPairFromSaltedPasswordGenerator {
550 KeyPairFromSaltedPasswordGenerator {
551 scrypt_params: ScryptParams::default(),
552 }
553 }
554
555 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 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 pub fn generate(&self, salted_password: SaltedPassword) -> Ed25519KeyPair {
582 let seed = self.generate_seed(
584 salted_password.password.as_bytes(),
585 salted_password.salt.as_bytes(),
586 );
587 KeyPairFromSeed32Generator::generate(seed)
589 }
590}
591
592#[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 let seed = unwrap!(Seed32::from_base58(seed58));
612 assert_eq!(seed.to_base58(), seed58);
613
614 assert_eq!(
616 "DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV".to_owned(),
617 format!("{}", seed)
618 );
619 assert_eq!(
620 "Seed32 { DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV }".to_owned(),
621 format!("{:?}", seed)
622 );
623
624 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 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 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 assert_eq!(
725 bincode::serialize(&public_key)?,
726 public_key.to_bytes_vector(),
727 );
728
729 assert_eq!(
731 "PublicKey { DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV }".to_owned(),
732 format!("{:?}", public_key)
733 );
734
735 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 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 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 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 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); bincode::deserialize::<Sig>(&bin_sig)
795 .expect_err("Deserialization must be fail because length is invalid !");
796
797 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 assert_eq!(
884 "(EA7Dsw39ShZg4SpURsrgMaMqrweJPUFPYHwZA8e92e3D, hidden)".to_owned(),
885 format!("{}", key_pair2)
886 );
887
888 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 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 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}