1use core::marker::PhantomData;
21
22use crate::crypto::{
23 ByteArray, CryptoType, DeriveError, DeriveJunction, Pair as PairT, Public as PublicT,
24 PublicBytes, SecretStringError, Signature as SignatureT, SignatureBytes, UncheckedFrom,
25};
26
27use crate::proof_of_possession::{ProofOfPossessionGenerator, ProofOfPossessionVerifier};
28
29use alloc::vec::Vec;
30
31#[cfg(feature = "bls-experimental")]
33pub mod ecdsa_bls377 {
34 use crate::{bls377, crypto::CryptoTypeId, ecdsa};
35 #[cfg(feature = "full_crypto")]
36 use crate::{
37 crypto::{Pair as PairT, UncheckedFrom},
38 Hasher,
39 };
40
41 pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecb7");
43
44 const PUBLIC_KEY_LEN: usize =
45 ecdsa::PUBLIC_KEY_SERIALIZED_SIZE + bls377::PUBLIC_KEY_SERIALIZED_SIZE;
46 const SIGNATURE_LEN: usize =
47 ecdsa::SIGNATURE_SERIALIZED_SIZE + bls377::SIGNATURE_SERIALIZED_SIZE;
48
49 const POP_LEN: usize =
50 ecdsa::SIGNATURE_SERIALIZED_SIZE + bls377::PROOF_OF_POSSESSION_SERIALIZED_SIZE;
51
52 #[doc(hidden)]
53 pub struct EcdsaBls377Tag(ecdsa::EcdsaTag, bls377::Bls377Tag);
54
55 impl super::PairedCryptoSubTagBound for EcdsaBls377Tag {}
56
57 pub type Pair = super::Pair<
59 ecdsa::Pair,
60 bls377::Pair,
61 PUBLIC_KEY_LEN,
62 SIGNATURE_LEN,
63 POP_LEN,
64 EcdsaBls377Tag,
65 >;
66
67 pub type Public = super::Public<PUBLIC_KEY_LEN, EcdsaBls377Tag>;
69
70 pub type Signature = super::Signature<SIGNATURE_LEN, EcdsaBls377Tag>;
72
73 pub type ProofOfPossession = super::Signature<POP_LEN, EcdsaBls377Tag>;
75
76 impl super::CryptoType for Public {
77 type Pair = Pair;
78 }
79
80 impl super::CryptoType for Signature {
81 type Pair = Pair;
82 }
83
84 impl super::CryptoType for ProofOfPossession {
85 type Pair = Pair;
86 }
87
88 impl super::CryptoType for Pair {
89 type Pair = Pair;
90 }
91
92 #[cfg(feature = "full_crypto")]
93 impl Pair {
94 pub fn sign_with_hasher<H>(&self, message: &[u8]) -> Signature
100 where
101 H: Hasher,
102 H::Out: Into<[u8; 32]>,
103 {
104 let msg_hash = H::hash(message).into();
105
106 let mut raw: [u8; SIGNATURE_LEN] = [0u8; SIGNATURE_LEN];
107 raw[..ecdsa::SIGNATURE_SERIALIZED_SIZE]
108 .copy_from_slice(self.left.sign_prehashed(&msg_hash).as_ref());
109 raw[ecdsa::SIGNATURE_SERIALIZED_SIZE..]
110 .copy_from_slice(self.right.sign(message).as_ref());
111 <Self as PairT>::Signature::unchecked_from(raw)
112 }
113
114 pub fn verify_with_hasher<H>(sig: &Signature, message: &[u8], public: &Public) -> bool
120 where
121 H: Hasher,
122 H::Out: Into<[u8; 32]>,
123 {
124 let msg_hash = H::hash(message).into();
125
126 let Ok(left_pub) = public.0[..ecdsa::PUBLIC_KEY_SERIALIZED_SIZE].try_into() else {
127 return false
128 };
129 let Ok(left_sig) = sig.0[..ecdsa::SIGNATURE_SERIALIZED_SIZE].try_into() else {
130 return false
131 };
132 if !ecdsa::Pair::verify_prehashed(&left_sig, &msg_hash, &left_pub) {
133 return false
134 }
135
136 let Ok(right_pub) = public.0[ecdsa::PUBLIC_KEY_SERIALIZED_SIZE..].try_into() else {
137 return false
138 };
139 let Ok(right_sig) = sig.0[ecdsa::SIGNATURE_SERIALIZED_SIZE..].try_into() else {
140 return false
141 };
142 bls377::Pair::verify(&right_sig, message, &right_pub)
143 }
144 }
145}
146
147#[cfg(feature = "bls-experimental")]
149pub mod ecdsa_bls381 {
150 use crate::{bls381, crypto::CryptoTypeId, ecdsa};
151 #[cfg(feature = "full_crypto")]
152 use crate::{
153 crypto::{Pair as PairT, UncheckedFrom},
154 Hasher,
155 };
156
157 pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecb8");
159
160 pub const PUBLIC_KEY_LEN: usize =
162 ecdsa::PUBLIC_KEY_SERIALIZED_SIZE + bls381::PUBLIC_KEY_SERIALIZED_SIZE;
163
164 pub const SIGNATURE_LEN: usize =
166 ecdsa::SIGNATURE_SERIALIZED_SIZE + bls381::SIGNATURE_SERIALIZED_SIZE;
167
168 pub const POP_LEN: usize =
171 ecdsa::SIGNATURE_SERIALIZED_SIZE + bls381::PROOF_OF_POSSESSION_SERIALIZED_SIZE;
172
173 #[doc(hidden)]
174 pub struct EcdsaBls381Tag(ecdsa::EcdsaTag, bls381::Bls381Tag);
175
176 impl super::PairedCryptoSubTagBound for EcdsaBls381Tag {}
177
178 pub type Pair = super::Pair<
180 ecdsa::Pair,
181 bls381::Pair,
182 PUBLIC_KEY_LEN,
183 SIGNATURE_LEN,
184 POP_LEN,
185 EcdsaBls381Tag,
186 >;
187
188 pub type Public = super::Public<PUBLIC_KEY_LEN, EcdsaBls381Tag>;
190
191 pub type Signature = super::Signature<SIGNATURE_LEN, EcdsaBls381Tag>;
193
194 pub type ProofOfPossession = super::Signature<POP_LEN, EcdsaBls381Tag>;
196
197 impl super::CryptoType for Public {
198 type Pair = Pair;
199 }
200
201 impl super::CryptoType for Signature {
202 type Pair = Pair;
203 }
204
205 impl super::CryptoType for ProofOfPossession {
206 type Pair = Pair;
207 }
208
209 impl super::CryptoType for Pair {
210 type Pair = Pair;
211 }
212
213 #[cfg(feature = "full_crypto")]
214 impl Pair {
215 pub fn sign_with_hasher<H>(&self, message: &[u8]) -> Signature
221 where
222 H: Hasher,
223 H::Out: Into<[u8; 32]>,
224 {
225 let msg_hash = H::hash(message).into();
226
227 let mut raw: [u8; SIGNATURE_LEN] = [0u8; SIGNATURE_LEN];
228 raw[..ecdsa::SIGNATURE_SERIALIZED_SIZE]
229 .copy_from_slice(self.left.sign_prehashed(&msg_hash).as_ref());
230 raw[ecdsa::SIGNATURE_SERIALIZED_SIZE..]
231 .copy_from_slice(self.right.sign(message).as_ref());
232 <Self as PairT>::Signature::unchecked_from(raw)
233 }
234
235 pub fn verify_with_hasher<H>(sig: &Signature, message: &[u8], public: &Public) -> bool
241 where
242 H: Hasher,
243 H::Out: Into<[u8; 32]>,
244 {
245 let msg_hash = H::hash(message).into();
246
247 let Ok(left_pub) = public.0[..ecdsa::PUBLIC_KEY_SERIALIZED_SIZE].try_into() else {
248 return false
249 };
250 let Ok(left_sig) = sig.0[..ecdsa::SIGNATURE_SERIALIZED_SIZE].try_into() else {
251 return false
252 };
253 if !ecdsa::Pair::verify_prehashed(&left_sig, &msg_hash, &left_pub) {
254 return false
255 }
256
257 let Ok(right_pub) = public.0[ecdsa::PUBLIC_KEY_SERIALIZED_SIZE..].try_into() else {
258 return false
259 };
260 let Ok(right_sig) = sig.0[ecdsa::SIGNATURE_SERIALIZED_SIZE..].try_into() else {
261 return false
262 };
263 bls381::Pair::verify(&right_sig, message, &right_pub)
264 }
265 }
266}
267
268const SECURE_SEED_LEN: usize = 32;
272
273type Seed = [u8; SECURE_SEED_LEN];
279
280#[doc(hidden)]
281pub trait PairedCryptoSubTagBound {}
282#[doc(hidden)]
283pub struct PairedCryptoTag;
284
285pub type Public<const LEFT_PLUS_RIGHT_LEN: usize, SubTag> =
287 PublicBytes<LEFT_PLUS_RIGHT_LEN, (PairedCryptoTag, SubTag)>;
288
289impl<
290 LeftPair: PairT,
291 RightPair: PairT,
292 const LEFT_PLUS_RIGHT_PUBLIC_LEN: usize,
293 const SIGNATURE_LEN: usize,
294 const POP_LEN: usize,
295 SubTag: PairedCryptoSubTagBound,
296 > From<Pair<LeftPair, RightPair, LEFT_PLUS_RIGHT_PUBLIC_LEN, SIGNATURE_LEN, POP_LEN, SubTag>>
297 for Public<LEFT_PLUS_RIGHT_PUBLIC_LEN, SubTag>
298where
299 Pair<LeftPair, RightPair, LEFT_PLUS_RIGHT_PUBLIC_LEN, SIGNATURE_LEN, POP_LEN, SubTag>:
300 PairT<Public = Public<LEFT_PLUS_RIGHT_PUBLIC_LEN, SubTag>>,
301{
302 fn from(
303 x: Pair<LeftPair, RightPair, LEFT_PLUS_RIGHT_PUBLIC_LEN, SIGNATURE_LEN, POP_LEN, SubTag>,
304 ) -> Self {
305 x.public()
306 }
307}
308
309pub type Signature<const LEFT_PLUS_RIGHT_LEN: usize, SubTag> =
311 SignatureBytes<LEFT_PLUS_RIGHT_LEN, (PairedCryptoTag, SubTag)>;
312
313pub type ProofOfPossession<const LEFT_PLUS_RIGHT_LEN: usize, SubTag> =
315 SignatureBytes<LEFT_PLUS_RIGHT_LEN, (PairedCryptoTag, SubTag)>;
316
317pub struct Pair<
319 LeftPair: PairT,
320 RightPair: PairT,
321 const PUBLIC_KEY_LEN: usize,
322 const SIGNATURE_LEN: usize,
323 const POP_LEN: usize,
324 SubTag,
325> {
326 left: LeftPair,
327 right: RightPair,
328 _phantom: PhantomData<fn() -> SubTag>,
329}
330
331impl<
333 LeftPair: PairT + Clone,
334 RightPair: PairT + Clone,
335 const PUBLIC_KEY_LEN: usize,
336 const SIGNATURE_LEN: usize,
337 const POP_LEN: usize,
338 SubTag,
339 > Clone for Pair<LeftPair, RightPair, PUBLIC_KEY_LEN, SIGNATURE_LEN, POP_LEN, SubTag>
340{
341 fn clone(&self) -> Self {
342 Self { left: self.left.clone(), right: self.right.clone(), _phantom: PhantomData }
343 }
344}
345
346impl<
348 LeftPair: PairT,
349 RightPair: PairT,
350 const PUBLIC_KEY_LEN: usize,
351 const SIGNATURE_LEN: usize,
352 const POP_LEN: usize,
353 SubTag: PairedCryptoSubTagBound,
354 > PairT for Pair<LeftPair, RightPair, PUBLIC_KEY_LEN, SIGNATURE_LEN, POP_LEN, SubTag>
355where
356 Pair<LeftPair, RightPair, PUBLIC_KEY_LEN, SIGNATURE_LEN, POP_LEN, SubTag>: CryptoType,
357 Public<PUBLIC_KEY_LEN, SubTag>: PublicT,
358 Signature<SIGNATURE_LEN, SubTag>: SignatureT,
359 ProofOfPossession<POP_LEN, SubTag>: SignatureT,
360 LeftPair::Seed: From<Seed> + Into<Seed>,
361 RightPair::Seed: From<Seed> + Into<Seed>,
362{
363 type Seed = Seed;
364 type Public = Public<PUBLIC_KEY_LEN, SubTag>;
365 type Signature = Signature<SIGNATURE_LEN, SubTag>;
366 type ProofOfPossession = Signature<POP_LEN, SubTag>;
367
368 fn from_seed_slice(seed_slice: &[u8]) -> Result<Self, SecretStringError> {
369 if seed_slice.len() != SECURE_SEED_LEN {
370 return Err(SecretStringError::InvalidSeedLength)
371 }
372 let left = LeftPair::from_seed_slice(&seed_slice)?;
373 let right = RightPair::from_seed_slice(&seed_slice)?;
374 Ok(Pair { left, right, _phantom: PhantomData })
375 }
376
377 fn derive<Iter: Iterator<Item = DeriveJunction>>(
382 &self,
383 path: Iter,
384 seed: Option<Self::Seed>,
385 ) -> Result<(Self, Option<Self::Seed>), DeriveError> {
386 let left_path: Vec<_> = path.collect();
387 let right_path: Vec<_> = left_path.clone();
388
389 let left = self.left.derive(left_path.into_iter(), seed.map(|s| s.into()))?;
390 let right = self.right.derive(right_path.into_iter(), seed.map(|s| s.into()))?;
391
392 let seed = match (left.1, right.1) {
393 (Some(l), Some(r)) if l.as_ref() == r.as_ref() => Some(l.into()),
394 _ => None,
395 };
396
397 Ok((Self { left: left.0, right: right.0, _phantom: PhantomData }, seed))
398 }
399
400 fn public(&self) -> Self::Public {
401 let mut raw = [0u8; PUBLIC_KEY_LEN];
402 let left_pub = self.left.public();
403 let right_pub = self.right.public();
404 raw[..LeftPair::Public::LEN].copy_from_slice(left_pub.as_ref());
405 raw[LeftPair::Public::LEN..].copy_from_slice(right_pub.as_ref());
406 Self::Public::unchecked_from(raw)
407 }
408
409 #[cfg(feature = "full_crypto")]
410 fn sign(&self, message: &[u8]) -> Self::Signature {
411 let mut raw: [u8; SIGNATURE_LEN] = [0u8; SIGNATURE_LEN];
412 raw[..LeftPair::Signature::LEN].copy_from_slice(self.left.sign(message).as_ref());
413 raw[LeftPair::Signature::LEN..].copy_from_slice(self.right.sign(message).as_ref());
414 Self::Signature::unchecked_from(raw)
415 }
416
417 fn verify<Msg: AsRef<[u8]>>(
418 sig: &Self::Signature,
419 message: Msg,
420 public: &Self::Public,
421 ) -> bool {
422 let Ok(left_pub) = public.0[..LeftPair::Public::LEN].try_into() else { return false };
423 let Ok(left_sig) = sig.0[0..LeftPair::Signature::LEN].try_into() else { return false };
424 if !LeftPair::verify(&left_sig, message.as_ref(), &left_pub) {
425 return false
426 }
427
428 let Ok(right_pub) = public.0[LeftPair::Public::LEN..].try_into() else { return false };
429 let Ok(right_sig) = sig.0[LeftPair::Signature::LEN..].try_into() else { return false };
430 RightPair::verify(&right_sig, message.as_ref(), &right_pub)
431 }
432
433 fn to_raw_vec(&self) -> Vec<u8> {
435 let mut raw = self.left.to_raw_vec();
436 raw.extend(self.right.to_raw_vec());
437 raw
438 }
439}
440
441impl<
442 LeftPair: PairT + ProofOfPossessionGenerator,
443 RightPair: PairT + ProofOfPossessionGenerator,
444 const PUBLIC_KEY_LEN: usize,
445 const SIGNATURE_LEN: usize,
446 const POP_LEN: usize,
447 SubTag: PairedCryptoSubTagBound,
448 > ProofOfPossessionGenerator
449 for Pair<LeftPair, RightPair, PUBLIC_KEY_LEN, SIGNATURE_LEN, POP_LEN, SubTag>
450where
451 Pair<LeftPair, RightPair, PUBLIC_KEY_LEN, SIGNATURE_LEN, POP_LEN, SubTag>: CryptoType,
452 Public<PUBLIC_KEY_LEN, SubTag>: PublicT,
453 Signature<SIGNATURE_LEN, SubTag>: SignatureT,
454 ProofOfPossession<POP_LEN, SubTag>: SignatureT,
455 LeftPair::Seed: From<Seed> + Into<Seed>,
456 RightPair::Seed: From<Seed> + Into<Seed>,
457{
458 #[cfg(feature = "full_crypto")]
459 fn generate_proof_of_possession(&mut self, owner: &[u8]) -> Self::ProofOfPossession {
460 let mut raw: [u8; POP_LEN] = [0u8; POP_LEN];
461
462 raw.copy_from_slice(
463 [
464 self.left.generate_proof_of_possession(owner).to_raw_vec(),
465 self.right.generate_proof_of_possession(owner).to_raw_vec(),
466 ]
467 .concat()
468 .as_slice(),
469 );
470 Self::ProofOfPossession::unchecked_from(raw)
471 }
472}
473
474impl<
478 LeftPair: PairT + ProofOfPossessionVerifier,
479 RightPair: PairT + ProofOfPossessionVerifier,
480 const PUBLIC_KEY_LEN: usize,
481 const SIGNATURE_LEN: usize,
482 const POP_LEN: usize,
483 SubTag: PairedCryptoSubTagBound,
484 > ProofOfPossessionVerifier
485 for Pair<LeftPair, RightPair, PUBLIC_KEY_LEN, SIGNATURE_LEN, POP_LEN, SubTag>
486where
487 Pair<LeftPair, RightPair, PUBLIC_KEY_LEN, SIGNATURE_LEN, POP_LEN, SubTag>: CryptoType,
488 Public<PUBLIC_KEY_LEN, SubTag>: PublicT,
489 Signature<SIGNATURE_LEN, SubTag>: SignatureT,
490 ProofOfPossession<POP_LEN, SubTag>: SignatureT,
491 LeftPair::Seed: From<Seed> + Into<Seed>,
492 RightPair::Seed: From<Seed> + Into<Seed>,
493{
494 fn verify_proof_of_possession(
495 owner: &[u8],
496 proof_of_possession: &Self::ProofOfPossession,
497 allegedly_possessed_pubkey: &Self::Public,
498 ) -> bool {
499 let Ok(left_pub) = allegedly_possessed_pubkey.0[..LeftPair::Public::LEN].try_into() else {
500 return false
501 };
502 let Ok(left_proof_of_possession) =
503 proof_of_possession.0[0..LeftPair::ProofOfPossession::LEN].try_into()
504 else {
505 return false
506 };
507
508 if !LeftPair::verify_proof_of_possession(owner, &left_proof_of_possession, &left_pub) {
509 return false
510 }
511
512 let Ok(right_pub) = allegedly_possessed_pubkey.0[LeftPair::Public::LEN..].try_into() else {
513 return false
514 };
515 let Ok(right_proof_of_possession) =
516 proof_of_possession.0[LeftPair::ProofOfPossession::LEN..].try_into()
517 else {
518 return false
519 };
520 RightPair::verify_proof_of_possession(owner, &right_proof_of_possession, &right_pub)
521 }
522}
523
524#[cfg(all(test, feature = "bls-experimental"))]
526mod tests {
527 use super::*;
528 #[cfg(feature = "serde")]
529 use crate::crypto::Ss58Codec;
530 use crate::{bls377, crypto::DEV_PHRASE, ecdsa, KeccakHasher};
531 use codec::{Decode, Encode};
532 use ecdsa_bls377::{Pair, Signature};
533
534 #[test]
535 fn test_length_of_paired_ecdsa_and_bls377_public_key_and_signature_is_correct() {
536 assert_eq!(
537 <Pair as PairT>::Public::LEN,
538 <ecdsa::Pair as PairT>::Public::LEN + <bls377::Pair as PairT>::Public::LEN
539 );
540 assert_eq!(
541 <Pair as PairT>::Signature::LEN,
542 <ecdsa::Pair as PairT>::Signature::LEN + <bls377::Pair as PairT>::Signature::LEN
543 );
544 }
545
546 #[test]
547 fn default_phrase_should_be_used() {
548 assert_eq!(
549 Pair::from_string("//Alice///password", None).unwrap().public(),
550 Pair::from_string(&format!("{}//Alice", DEV_PHRASE), Some("password"))
551 .unwrap()
552 .public(),
553 );
554 }
555
556 #[test]
557 fn generate_with_phrase_should_be_recoverable_with_from_string() {
558 let (pair, phrase, seed) = Pair::generate_with_phrase(None);
559 let repair_seed = Pair::from_seed_slice(seed.as_ref()).expect("seed slice is valid");
560 assert_eq!(pair.public(), repair_seed.public());
561 assert_eq!(pair.to_raw_vec(), repair_seed.to_raw_vec());
562
563 let (repair_phrase, reseed) =
564 Pair::from_phrase(phrase.as_ref(), None).expect("seed slice is valid");
565 assert_eq!(seed, reseed);
566 assert_eq!(pair.public(), repair_phrase.public());
567 assert_eq!(pair.to_raw_vec(), repair_seed.to_raw_vec());
568 let repair_string = Pair::from_string(phrase.as_str(), None).expect("seed slice is valid");
569 assert_eq!(pair.public(), repair_string.public());
570 assert_eq!(pair.to_raw_vec(), repair_seed.to_raw_vec());
571 }
572
573 #[test]
574 fn seed_and_derive_should_work() {
575 let seed_for_right_and_left: [u8; SECURE_SEED_LEN] = array_bytes::hex2array_unchecked(
576 "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60",
577 );
578 let pair = Pair::from_seed(&seed_for_right_and_left);
579 let path = vec![DeriveJunction::Hard([0u8; 32])];
582 let derived = pair.derive(path.into_iter(), None).ok().unwrap().0;
583 assert_eq!(
584 derived.to_raw_vec(),
585 [
586 array_bytes::hex2array_unchecked::<&str, SECURE_SEED_LEN>(
587 "b8eefc4937200a8382d00050e050ced2d4ab72cc2ef1b061477afb51564fdd61"
588 ),
589 array_bytes::hex2array_unchecked::<&str, SECURE_SEED_LEN>(
590 "3a0626d095148813cd1642d38254f1cfff7eb8cc1a2fc83b2a135377c3554c12"
591 )
592 ]
593 .concat()
594 );
595 }
596
597 #[test]
598 fn test_vector_should_work() {
599 let seed_left_and_right: [u8; SECURE_SEED_LEN] = array_bytes::hex2array_unchecked(
600 "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60",
601 );
602 let pair = Pair::from_seed(&([seed_left_and_right].concat()[..].try_into().unwrap()));
603 let public = pair.public();
604 assert_eq!(
605 public,
606 Public::unchecked_from(
607 array_bytes::hex2array_unchecked("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd917a84ca8ce4c37c93c95ecee6a3c0c9a7b9c225093cf2f12dc4f69cbfb847ef9424a18f5755d5a742247d386ff2aabb806bcf160eff31293ea9616976628f77266c8a8cc1d8753be04197bd6cdd8c5c87a148f782c4c1568d599b48833fd539001e580cff64bbc71850605433fcd051f3afc3b74819786f815ffb5272030a8d03e5df61e6183f8fd8ea85f26defa83400"),
608 ),
609 );
610 let message = b"";
611 let signature =
612 array_bytes::hex2array_unchecked("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00124571b4bf23083b5d07e720fde0a984d4d592868156ece77487e97a1ba4b29397dbdc454f13e3aed1ad4b6a99af2501c68ab88ec0495f962a4f55c7c460275a8d356cfa344c27778ca4c641bd9a3604ce5c28f9ed566e1d29bf3b5d3591e46ae28be3ece035e8e4db53a40fc5826002"
613 );
614 let signature = Signature::unchecked_from(signature);
615 assert!(pair.sign(&message[..]) == signature);
616 assert!(Pair::verify(&signature, &message[..], &public));
617 }
618
619 #[test]
620 fn test_vector_by_string_should_work() {
621 let pair = Pair::from_string(
622 "0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60",
623 None,
624 )
625 .unwrap();
626 let public = pair.public();
627 assert_eq!(
628 public,
629 Public::unchecked_from(
630 array_bytes::hex2array_unchecked("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd917a84ca8ce4c37c93c95ecee6a3c0c9a7b9c225093cf2f12dc4f69cbfb847ef9424a18f5755d5a742247d386ff2aabb806bcf160eff31293ea9616976628f77266c8a8cc1d8753be04197bd6cdd8c5c87a148f782c4c1568d599b48833fd539001e580cff64bbc71850605433fcd051f3afc3b74819786f815ffb5272030a8d03e5df61e6183f8fd8ea85f26defa83400"
631 ),
632 ),
633 );
634 let message = b"";
635 let signature =
636 array_bytes::hex2array_unchecked("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00124571b4bf23083b5d07e720fde0a984d4d592868156ece77487e97a1ba4b29397dbdc454f13e3aed1ad4b6a99af2501c68ab88ec0495f962a4f55c7c460275a8d356cfa344c27778ca4c641bd9a3604ce5c28f9ed566e1d29bf3b5d3591e46ae28be3ece035e8e4db53a40fc5826002"
637 );
638 let signature = Signature::unchecked_from(signature);
639 assert!(pair.sign(&message[..]) == signature);
640 assert!(Pair::verify(&signature, &message[..], &public));
641 }
642
643 #[test]
644 fn generated_pair_should_work() {
645 let (pair, _) = Pair::generate();
646 let public = pair.public();
647 let message = b"Something important";
648 let signature = pair.sign(&message[..]);
649 assert!(Pair::verify(&signature, &message[..], &public));
650 assert!(!Pair::verify(&signature, b"Something else", &public));
651 }
652
653 #[test]
654 fn seeded_pair_should_work() {
655 let pair =
656 Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap()));
657 let public = pair.public();
658 assert_eq!(
659 public,
660 Public::unchecked_from(
661 array_bytes::hex2array_unchecked("035676109c54b9a16d271abeb4954316a40a32bcce023ac14c8e26e958aa68fba9754d2f2bbfa67df54d7e0e951979a18a1e0f45948857752cc2bac6bbb0b1d05e8e48bcc453920bf0c4bbd5993212480112a1fb433f04d74af0a8b700d93dc957ab3207f8d071e948f5aca1a7632c00bdf6d06be05b43e2e6216dccc8a5d55a0071cb2313cfd60b7e9114619cd17c06843b352f0b607a99122f6651df8f02e1ad3697bd208e62af047ddd7b942ba80080")
662 ),
663 );
664 let message =
665 array_bytes::hex2bytes_unchecked("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000"
666 );
667 let signature = pair.sign(&message[..]);
668 println!("Correct signature: {:?}", signature);
669 assert!(Pair::verify(&signature, &message[..], &public));
670 assert!(!Pair::verify(&signature, "Other message", &public));
671 }
672
673 #[test]
674 fn generate_with_phrase_recovery_possible() {
675 let (pair1, phrase, _) = Pair::generate_with_phrase(None);
676 let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap();
677
678 assert_eq!(pair1.public(), pair2.public());
679 }
680
681 #[test]
682 fn generate_with_password_phrase_recovery_possible() {
683 let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password"));
684 let (pair2, _) = Pair::from_phrase(&phrase, Some("password")).unwrap();
685
686 assert_eq!(pair1.public(), pair2.public());
687 }
688
689 #[test]
690 fn password_does_something() {
691 let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password"));
692 let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap();
693
694 assert_ne!(pair1.public(), pair2.public());
695 assert_ne!(pair1.to_raw_vec(), pair2.to_raw_vec());
696 }
697
698 #[test]
699 fn ss58check_roundtrip_works() {
700 let pair =
701 Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap()));
702 let public = pair.public();
703 let s = public.to_ss58check();
704 println!("Correct: {}", s);
705 let cmp = Public::from_ss58check(&s).unwrap();
706 assert_eq!(cmp, public);
707 }
708
709 #[test]
710 fn sign_and_verify_with_hasher_works() {
711 let pair =
712 Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap()));
713 let message = b"Something important";
714 let signature = pair.sign_with_hasher::<KeccakHasher>(&message[..]);
715
716 assert!(Pair::verify_with_hasher::<KeccakHasher>(&signature, &message[..], &pair.public()));
717 }
718
719 #[test]
720 fn signature_serialization_works() {
721 let pair =
722 Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap()));
723 let message = b"Something important";
724 let signature = pair.sign(&message[..]);
725
726 let serialized_signature = serde_json::to_string(&signature).unwrap();
727 println!("{:?} -- {:}", signature.0, serialized_signature);
728 assert_eq!(serialized_signature.len(), 356);
730 let signature = serde_json::from_str(&serialized_signature).unwrap();
731 assert!(Pair::verify(&signature, &message[..], &pair.public()));
732 }
733
734 #[test]
735 fn signature_serialization_doesnt_panic() {
736 fn deserialize_signature(text: &str) -> Result<Signature, serde_json::error::Error> {
737 serde_json::from_str(text)
738 }
739 assert!(deserialize_signature("Not valid json.").is_err());
740 assert!(deserialize_signature("\"Not an actual signature.\"").is_err());
741 assert!(deserialize_signature("\"abc123\"").is_err());
743 }
744
745 #[test]
746 fn encode_and_decode_public_key_works() {
747 let pair =
748 Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap()));
749 let public = pair.public();
750 let encoded_public = public.encode();
751 let decoded_public = Public::decode(&mut encoded_public.as_slice()).unwrap();
752 assert_eq!(public, decoded_public)
753 }
754
755 #[test]
756 fn encode_and_decode_signature_works() {
757 let pair =
758 Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap()));
759 let message = b"Something important";
760 let signature = pair.sign(&message[..]);
761 let encoded_signature = signature.encode();
762 let decoded_signature = Signature::decode(&mut encoded_signature.as_slice()).unwrap();
763 assert_eq!(signature, decoded_signature)
764 }
765
766 #[test]
767 fn good_proof_of_possession_should_work_bad_proof_of_possession_should_fail() {
768 let owner = b"owner";
769 let not_owner = b"not owner";
770
771 let mut pair = Pair::from_seed(b"12345678901234567890123456789012");
772 let other_pair = Pair::from_seed(b"23456789012345678901234567890123");
773 let proof_of_possession = pair.generate_proof_of_possession(owner);
774 assert!(Pair::verify_proof_of_possession(owner, &proof_of_possession, &pair.public()));
775 assert_eq!(
776 Pair::verify_proof_of_possession(owner, &proof_of_possession, &other_pair.public()),
777 false
778 );
779 assert!(!Pair::verify_proof_of_possession(not_owner, &proof_of_possession, &pair.public()));
780 }
781}