1use crate::{
21 crypto::{
22 CryptoType, CryptoTypeId, DeriveError, DeriveJunction, Pair as TraitPair, PublicBytes,
23 SecretStringError, SignatureBytes,
24 },
25 proof_of_possession::NonAggregatable,
26};
27
28#[cfg(not(feature = "std"))]
29use alloc::vec::Vec;
30use k256::ecdsa::{SigningKey as SecretKey, VerifyingKey};
31
32#[cfg(feature = "full_crypto")]
33type NativeSignature = (k256::ecdsa::Signature, k256::ecdsa::RecoveryId);
34
35pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecds");
37
38pub const PUBLIC_KEY_SERIALIZED_SIZE: usize = 33;
40
41pub const SIGNATURE_SERIALIZED_SIZE: usize = 65;
43
44pub fn is_signature_normalized(sig: &[u8; 65]) -> bool {
47 let Ok(parsed) = k256::ecdsa::Signature::try_from(&sig[..64]) else {
48 return false;
49 };
50 parsed.normalize_s().is_none()
51}
52
53#[doc(hidden)]
54#[derive(Clone)]
55pub struct EcdsaTag;
56
57#[doc(hidden)]
58#[derive(Clone)]
59pub struct EcdsaKeccakTag;
60
61type Seed = [u8; 32];
65
66#[doc(hidden)]
67pub type GenericPublic<TAG> = PublicBytes<PUBLIC_KEY_SERIALIZED_SIZE, TAG>;
68
69pub type Public = GenericPublic<EcdsaTag>;
73
74pub type KeccakPublic = GenericPublic<EcdsaKeccakTag>;
78
79impl<TAG> GenericPublic<TAG> {
80 pub fn from_full(full: &[u8]) -> Result<Self, ()> {
84 let mut tagged_full = [0u8; 65];
85 let full = if full.len() == 64 {
86 tagged_full[0] = 0x04;
88 tagged_full[1..].copy_from_slice(full);
89 &tagged_full
90 } else {
91 full
92 };
93 let pubkey = VerifyingKey::from_sec1_bytes(&full);
94 pubkey.map(|k| k.into()).map_err(|_| ())
95 }
96}
97
98impl<TAG> PartialEq<[u8; 33]> for GenericPublic<TAG> {
99 fn eq(&self, other: &[u8; 33]) -> bool {
100 &self.0 == other
101 }
102}
103
104impl<TAG> From<VerifyingKey> for GenericPublic<TAG> {
105 fn from(pubkey: VerifyingKey) -> Self {
106 Self::try_from(&pubkey.to_sec1_bytes()[..])
107 .expect("Valid key is serializable to [u8; 33]. qed.")
108 }
109}
110
111#[cfg(feature = "full_crypto")]
112impl<TAG> From<GenericPair<GenericPublic<TAG>>> for GenericPublic<TAG> {
113 fn from(x: GenericPair<GenericPublic<TAG>>) -> Self {
114 x.public
115 }
116}
117
118#[doc(hidden)]
119pub type GenericSignature<PUBLIC> = SignatureBytes<SIGNATURE_SERIALIZED_SIZE, PUBLIC>;
120
121pub type Signature = GenericSignature<Public>;
125
126pub type KeccakSignature = GenericSignature<KeccakPublic>;
130
131pub trait Recover: seal::Sealed {
133 type Public;
135
136 fn recover_prehashed(&self, message: &[u8; 32]) -> Option<Self::Public>;
138
139 fn recover<M: AsRef<[u8]>>(&self, message: M) -> Option<Self::Public>;
141}
142
143impl<PUBLIC: From<VerifyingKey>> GenericSignature<PUBLIC> {
144 pub fn recover_prehashed(&self, message: &[u8; 32]) -> Option<PUBLIC> {
146 let rid = k256::ecdsa::RecoveryId::from_byte(self.0[64])?;
147 let sig = k256::ecdsa::Signature::from_bytes((&self.0[..64]).into()).ok()?;
148 let (sig, rid) = if let Some(normalized) = sig.normalize_s() {
151 (normalized, k256::ecdsa::RecoveryId::new(!rid.is_y_odd(), rid.is_x_reduced()))
152 } else {
153 (sig, rid)
154 };
155 VerifyingKey::recover_from_prehash(message, &sig, rid).map(From::from).ok()
156 }
157}
158
159pub type ProofOfPossession = Signature;
163
164pub type KeccakProofOfPossession = KeccakSignature;
168
169impl Signature {
170 pub fn recover<M: AsRef<[u8]>>(&self, message: M) -> Option<Public> {
172 self.recover_prehashed(&sp_crypto_hashing::blake2_256(message.as_ref()))
173 }
174}
175
176impl KeccakSignature {
177 pub fn recover<M: AsRef<[u8]>>(&self, message: M) -> Option<KeccakPublic> {
179 self.recover_prehashed(&sp_crypto_hashing::keccak_256(message.as_ref()))
180 }
181}
182
183impl Recover for Signature {
184 type Public = Public;
185
186 fn recover_prehashed(&self, message: &[u8; 32]) -> Option<Self::Public> {
187 self.recover_prehashed(message)
188 }
189
190 fn recover<M: AsRef<[u8]>>(&self, message: M) -> Option<Self::Public> {
191 self.recover(message)
192 }
193}
194
195impl Recover for KeccakSignature {
196 type Public = KeccakPublic;
197
198 fn recover_prehashed(&self, message: &[u8; 32]) -> Option<Self::Public> {
199 self.recover_prehashed(message)
200 }
201
202 fn recover<M: AsRef<[u8]>>(&self, message: M) -> Option<Self::Public> {
203 self.recover(message)
204 }
205}
206
207impl<PUBLIC> From<(k256::ecdsa::Signature, k256::ecdsa::RecoveryId)> for GenericSignature<PUBLIC> {
208 fn from(recsig: (k256::ecdsa::Signature, k256::ecdsa::RecoveryId)) -> Self {
209 let mut r = Self::default();
210 r.0[..64].copy_from_slice(&recsig.0.to_bytes());
211 r.0[64] = recsig.1.to_byte();
212 r
213 }
214}
215
216fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed {
218 use codec::Encode;
219 ("Secp256k1HDKD", secret_seed, cc).using_encoded(sp_crypto_hashing::blake2_256)
220}
221
222#[derive(Clone)]
223#[doc(hidden)]
224pub struct GenericPair<PUBLIC> {
225 public: PUBLIC,
226 secret: SecretKey,
227}
228
229pub type Pair = GenericPair<Public>;
231
232pub type KeccakPair = GenericPair<KeccakPublic>;
234
235impl TraitPair for Pair {
236 type Public = Public;
237 type Seed = Seed;
238 type Signature = Signature;
239 type ProofOfPossession = ProofOfPossession;
240
241 fn from_seed_slice(seed_slice: &[u8]) -> Result<Self, SecretStringError> {
242 Self::from_seed_slice(seed_slice)
243 }
244
245 fn derive<Iter: Iterator<Item = DeriveJunction>>(
246 &self,
247 path: Iter,
248 _seed: Option<Seed>,
249 ) -> Result<(Self, Option<Seed>), DeriveError> {
250 self.derive(path)
251 }
252
253 fn public(&self) -> Self::Public {
254 self.public
255 }
256
257 #[cfg(feature = "full_crypto")]
258 fn sign(&self, message: &[u8]) -> Self::Signature {
259 self.sign(message)
260 }
261
262 fn verify<M: AsRef<[u8]>>(sig: &Self::Signature, message: M, public: &Public) -> bool {
264 Self::verify(sig, message, public)
265 }
266
267 fn to_raw_vec(&self) -> Vec<u8> {
269 self.to_raw_vec()
270 }
271}
272
273impl TraitPair for KeccakPair {
274 type Public = KeccakPublic;
275 type Seed = Seed;
276 type Signature = KeccakSignature;
277 type ProofOfPossession = KeccakProofOfPossession;
278
279 fn from_seed_slice(seed_slice: &[u8]) -> Result<Self, SecretStringError> {
280 Self::from_seed_slice(seed_slice)
281 }
282
283 fn derive<Iter: Iterator<Item = DeriveJunction>>(
284 &self,
285 path: Iter,
286 _seed: Option<Seed>,
287 ) -> Result<(Self, Option<Seed>), DeriveError> {
288 self.derive(path)
289 }
290
291 fn public(&self) -> Self::Public {
292 self.public
293 }
294
295 #[cfg(feature = "full_crypto")]
296 fn sign(&self, message: &[u8]) -> Self::Signature {
297 self.sign(message)
298 }
299
300 fn verify<M: AsRef<[u8]>>(sig: &Self::Signature, message: M, public: &Self::Public) -> bool {
302 Self::verify(sig, message, public)
303 }
304
305 fn to_raw_vec(&self) -> Vec<u8> {
307 self.to_raw_vec()
308 }
309}
310
311impl<PUBLIC> GenericPair<PUBLIC>
312where
313 Self: TraitPair<Seed = Seed, Signature: Recover>,
314 <<Self as TraitPair>::Signature as Recover>::Public: PartialEq<PUBLIC>,
315 PUBLIC: PartialEq<[u8; 33]>,
316{
317 pub fn seed(&self) -> Seed {
319 self.secret.to_bytes().into()
320 }
321
322 #[cfg(feature = "std")]
325 pub fn from_legacy_string(s: &str, password_override: Option<&str>) -> Self {
326 Self::from_string(s, password_override).unwrap_or_else(|_| {
327 let mut padded_seed: Seed = [b' '; 32];
328 let len = s.len().min(32);
329 padded_seed[..len].copy_from_slice(&s.as_bytes()[..len]);
330 Self::from_seed(&padded_seed)
331 })
332 }
333
334 pub fn verify_prehashed(
337 sig: &<Self as TraitPair>::Signature,
338 message: &[u8; 32],
339 public: &PUBLIC,
340 ) -> bool {
341 match sig.recover_prehashed(message) {
342 Some(actual) => actual == *public,
343 None => false,
344 }
345 }
346
347 #[deprecated(note = "please use `verify` instead")]
350 pub fn verify_deprecated<M: AsRef<[u8]>>(sig: &Signature, message: M, pubkey: &Public) -> bool {
351 let message =
352 libsecp256k1::Message::parse(&sp_crypto_hashing::blake2_256(message.as_ref()));
353
354 let parse_signature_overflowing = |x: [u8; SIGNATURE_SERIALIZED_SIZE]| {
355 let sig = libsecp256k1::Signature::parse_overflowing_slice(&x[..64]).ok()?;
356 let rid = libsecp256k1::RecoveryId::parse(x[64]).ok()?;
357 Some((sig, rid))
358 };
359
360 let (sig, rid) = match parse_signature_overflowing(sig.0) {
361 Some(sigri) => sigri,
362 _ => return false,
363 };
364 match libsecp256k1::recover(&message, &sig, &rid) {
365 Ok(actual) => pubkey == &actual.serialize_compressed(),
366 _ => false,
367 }
368 }
369
370 fn derive<Iter: Iterator<Item = DeriveJunction>>(
371 &self,
372 path: Iter,
373 ) -> Result<(Self, Option<Seed>), DeriveError> {
374 let mut acc = self.seed();
375 for j in path {
376 match j {
377 DeriveJunction::Soft(_cc) => return Err(DeriveError::SoftKeyInPath),
378 DeriveJunction::Hard(cc) => acc = derive_hard_junction(&acc, &cc),
379 }
380 }
381 Ok((Self::from_seed(&acc), Some(acc)))
382 }
383
384 fn verify<M: AsRef<[u8]>>(
385 sig: &<Self as TraitPair>::Signature,
386 message: M,
387 public: &PUBLIC,
388 ) -> bool {
389 sig.recover(message).map(|actual| actual == *public).unwrap_or_default()
390 }
391
392 fn to_raw_vec(&self) -> Vec<u8> {
393 self.seed().to_vec()
394 }
395}
396
397impl<PUBLIC: From<VerifyingKey>> GenericPair<PUBLIC> {
398 fn from_seed_slice(seed_slice: &[u8]) -> Result<Self, SecretStringError> {
399 let secret =
400 SecretKey::from_slice(seed_slice).map_err(|_| SecretStringError::InvalidSeedLength)?;
401 Ok(Self { public: VerifyingKey::from(&secret).into(), secret })
402 }
403}
404
405#[cfg(feature = "full_crypto")]
406impl<PUBLIC> GenericPair<PUBLIC>
407where
408 Self: TraitPair,
409 <Self as TraitPair>::Signature: From<NativeSignature>,
410{
411 pub fn sign_prehashed(&self, message: &[u8; 32]) -> <Self as TraitPair>::Signature {
413 let (raw_sig, recovery_id) = self
414 .secret
415 .sign_prehash_recoverable(message)
416 .expect("Signing can't fail when using 32 bytes message hash. qed.");
417
418 let (normalized_sig, adjusted_v) = if let Some(normalized) = raw_sig.normalize_s() {
420 (
421 normalized,
422 k256::ecdsa::RecoveryId::new(!recovery_id.is_y_odd(), recovery_id.is_x_reduced()),
423 )
424 } else {
425 (raw_sig, recovery_id)
426 };
427 (normalized_sig, adjusted_v).into()
428 }
429}
430
431#[cfg(feature = "full_crypto")]
432impl Pair
433where
434 <Self as TraitPair>::Signature: From<NativeSignature>,
435{
436 fn sign(&self, message: &[u8]) -> Signature {
437 self.sign_prehashed(&sp_crypto_hashing::blake2_256(message))
438 }
439}
440
441#[cfg(feature = "full_crypto")]
442impl KeccakPair
443where
444 <Self as TraitPair>::Signature: From<NativeSignature>,
445{
446 fn sign(&self, message: &[u8]) -> KeccakSignature {
447 self.sign_prehashed(&sp_crypto_hashing::keccak_256(message))
448 }
449}
450
451impl CryptoType for Public {
452 type Pair = Pair;
453}
454
455impl CryptoType for KeccakPublic {
456 type Pair = KeccakPair;
457}
458
459impl CryptoType for Signature {
460 type Pair = Pair;
461}
462
463impl CryptoType for KeccakSignature {
464 type Pair = KeccakPair;
465}
466
467impl CryptoType for Pair {
468 type Pair = Self;
469}
470
471impl CryptoType for KeccakPair {
472 type Pair = Self;
473}
474
475impl NonAggregatable for Pair {}
476
477mod seal {
478 pub trait Sealed {}
479 impl Sealed for super::Signature {}
480 impl Sealed for super::KeccakSignature {}
481}
482
483#[cfg(test)]
484mod test {
485 use super::*;
486 use crate::{
487 crypto::{
488 set_default_ss58_version, PublicError, Ss58AddressFormat, Ss58AddressFormatRegistry,
489 Ss58Codec, DEV_PHRASE,
490 },
491 proof_of_possession::{ProofOfPossessionGenerator, ProofOfPossessionVerifier},
492 };
493 use serde_json;
494
495 #[test]
496 fn default_phrase_should_be_used() {
497 assert_eq!(
498 Pair::from_string("//Alice///password", None).unwrap().public(),
499 Pair::from_string(&format!("{}//Alice", DEV_PHRASE), Some("password"))
500 .unwrap()
501 .public(),
502 );
503 }
504
505 #[test]
506 fn seed_and_derive_should_work() {
507 let seed = array_bytes::hex2array_unchecked(
508 "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60",
509 );
510 let pair = Pair::from_seed(&seed);
511 assert_eq!(pair.seed(), seed);
512 let path = vec![DeriveJunction::Hard([0u8; 32])];
513 let derived = pair.derive(path.into_iter()).ok().unwrap();
514 assert_eq!(
515 derived.0.seed(),
516 array_bytes::hex2array_unchecked::<_, 32>(
517 "b8eefc4937200a8382d00050e050ced2d4ab72cc2ef1b061477afb51564fdd61"
518 )
519 );
520 }
521
522 #[test]
523 fn test_vector_should_work() {
524 let pair = Pair::from_seed(&array_bytes::hex2array_unchecked(
525 "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60",
526 ));
527 let public = pair.public();
528 assert_eq!(
529 public,
530 Public::from_full(
531 &array_bytes::hex2bytes_unchecked("8db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd913ebbe148dd17c56551a52952371071a6c604b3f3abe8f2c8fa742158ea6dd7d4"),
532 ).unwrap(),
533 );
534 let message = b"";
535 let signature = array_bytes::hex2array_unchecked("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00");
536 let signature = Signature::from_raw(signature);
537 assert!(pair.sign(&message[..]) == signature);
538 assert!(Pair::verify(&signature, &message[..], &public));
539 }
540
541 #[test]
542 fn test_vector_by_string_should_work() {
543 let pair = Pair::from_string(
544 "0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60",
545 None,
546 )
547 .unwrap();
548 let public = pair.public();
549 assert_eq!(
550 public,
551 Public::from_full(
552 &array_bytes::hex2bytes_unchecked("8db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd913ebbe148dd17c56551a52952371071a6c604b3f3abe8f2c8fa742158ea6dd7d4"),
553 ).unwrap(),
554 );
555 let message = b"";
556 let signature = array_bytes::hex2array_unchecked("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00");
557 let signature = Signature::from_raw(signature);
558 assert!(pair.sign(&message[..]) == signature);
559 assert!(Pair::verify(&signature, &message[..], &public));
560 }
561
562 #[test]
563 fn generated_pair_should_work() {
564 let (pair, _) = Pair::generate();
565 let public = pair.public();
566 let message = b"Something important";
567 let signature = pair.sign(&message[..]);
568 assert!(Pair::verify(&signature, &message[..], &public));
569 assert!(!Pair::verify(&signature, b"Something else", &public));
570 }
571
572 #[test]
573 fn generated_pair_should_work_keccak() {
574 let (pair, _) = KeccakPair::generate();
575 let public = pair.public();
576 let message = b"Something important";
577 let signature = pair.sign(&message[..]);
578 assert!(KeccakPair::verify(&signature, &message[..], &public));
579 assert!(!KeccakPair::verify(&signature, b"Something else", &public));
580 }
581
582 #[test]
583 fn seeded_pair_should_work() {
584 let pair = Pair::from_seed(b"12345678901234567890123456789012");
585 let public = pair.public();
586 assert_eq!(
587 public,
588 Public::from_full(
589 &array_bytes::hex2bytes_unchecked("5676109c54b9a16d271abeb4954316a40a32bcce023ac14c8e26e958aa68fba995840f3de562156558efbfdac3f16af0065e5f66795f4dd8262a228ef8c6d813"),
590 ).unwrap(),
591 );
592 let message = array_bytes::hex2bytes_unchecked("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000");
593 let signature = pair.sign(&message[..]);
594 println!("Correct signature: {:?}", signature);
595 assert!(Pair::verify(&signature, &message[..], &public));
596 assert!(!Pair::verify(&signature, "Other message", &public));
597 }
598
599 #[test]
600 fn generate_with_phrase_recovery_possible() {
601 let (pair1, phrase, _) = Pair::generate_with_phrase(None);
602 let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap();
603
604 assert_eq!(pair1.public(), pair2.public());
605 }
606
607 #[test]
608 fn generate_with_password_phrase_recovery_possible() {
609 let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password"));
610 let (pair2, _) = Pair::from_phrase(&phrase, Some("password")).unwrap();
611
612 assert_eq!(pair1.public(), pair2.public());
613 }
614
615 #[test]
616 fn generate_with_phrase_should_be_recoverable_with_from_string() {
617 let (pair, phrase, seed) = Pair::generate_with_phrase(None);
618 let repair_seed = Pair::from_seed_slice(seed.as_ref()).expect("seed slice is valid");
619 assert_eq!(pair.public(), repair_seed.public());
620 assert_eq!(pair.secret, repair_seed.secret);
621 let (repair_phrase, reseed) =
622 Pair::from_phrase(phrase.as_ref(), None).expect("seed slice is valid");
623 assert_eq!(seed, reseed);
624 assert_eq!(pair.public(), repair_phrase.public());
625 assert_eq!(pair.secret, repair_phrase.secret);
626 let repair_string = Pair::from_string(phrase.as_str(), None).expect("seed slice is valid");
627 assert_eq!(pair.public(), repair_string.public());
628 assert_eq!(pair.secret, repair_string.secret);
629 }
630
631 #[test]
632 fn password_does_something() {
633 let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password"));
634 let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap();
635
636 assert_ne!(pair1.public(), pair2.public());
637 assert_ne!(pair1.secret, pair2.secret);
638 }
639
640 #[test]
641 fn ss58check_roundtrip_works() {
642 let pair = Pair::from_seed(b"12345678901234567890123456789012");
643 let public = pair.public();
644 let s = public.to_ss58check();
645 println!("Correct: {}", s);
646 let cmp = Public::from_ss58check(&s).unwrap();
647 assert_eq!(cmp, public);
648 }
649
650 #[test]
651 fn ss58check_format_check_works() {
652 let pair = Pair::from_seed(b"12345678901234567890123456789012");
653 let public = pair.public();
654 let format = Ss58AddressFormatRegistry::Reserved46Account.into();
655 let s = public.to_ss58check_with_version(format);
656 assert_eq!(Public::from_ss58check_with_version(&s), Err(PublicError::FormatNotAllowed));
657 }
658
659 #[test]
660 fn ss58check_full_roundtrip_works() {
661 let pair = Pair::from_seed(b"12345678901234567890123456789012");
662 let public = pair.public();
663 let format = Ss58AddressFormatRegistry::PolkadotAccount.into();
664 let s = public.to_ss58check_with_version(format);
665 let (k, f) = Public::from_ss58check_with_version(&s).unwrap();
666 assert_eq!(k, public);
667 assert_eq!(f, format);
668
669 let format = Ss58AddressFormat::custom(64);
670 let s = public.to_ss58check_with_version(format);
671 let (k, f) = Public::from_ss58check_with_version(&s).unwrap();
672 assert_eq!(k, public);
673 assert_eq!(f, format);
674 }
675
676 #[test]
677 fn ss58check_custom_format_works() {
678 if std::env::var("RUN_CUSTOM_FORMAT_TEST") == Ok("1".into()) {
681 use crate::crypto::Ss58AddressFormat;
682 let default_format = crate::crypto::default_ss58_version();
684 set_default_ss58_version(Ss58AddressFormat::custom(200));
687 let addr = "4pbsSkWcBaYoFHrKJZp5fDVUKbqSYD9dhZZGvpp3vQ5ysVs5ybV";
689 Public::from_ss58check(addr).unwrap();
690
691 set_default_ss58_version(default_format);
692 let addr = "KWAfgC2aRG5UVD6CpbPQXCx4YZZUhvWqqAJE6qcYc9Rtr6g5C";
694 Public::from_ss58check(addr).unwrap();
695
696 println!("CUSTOM_FORMAT_SUCCESSFUL");
697 } else {
698 let executable = std::env::current_exe().unwrap();
699 let output = std::process::Command::new(executable)
700 .env("RUN_CUSTOM_FORMAT_TEST", "1")
701 .args(&["--nocapture", "ss58check_custom_format_works"])
702 .output()
703 .unwrap();
704
705 let output = String::from_utf8(output.stdout).unwrap();
706 assert!(output.contains("CUSTOM_FORMAT_SUCCESSFUL"));
707 }
708 }
709
710 #[test]
711 fn signature_serialization_works() {
712 let pair = Pair::from_seed(b"12345678901234567890123456789012");
713 let message = b"Something important";
714 let signature = pair.sign(&message[..]);
715 let serialized_signature = serde_json::to_string(&signature).unwrap();
716 assert_eq!(serialized_signature.len(), SIGNATURE_SERIALIZED_SIZE * 2 + 2);
718 let signature = serde_json::from_str(&serialized_signature).unwrap();
719 assert!(Pair::verify(&signature, &message[..], &pair.public()));
720 }
721
722 #[test]
723 fn signature_serialization_doesnt_panic() {
724 fn deserialize_signature(text: &str) -> Result<Signature, serde_json::error::Error> {
725 serde_json::from_str(text)
726 }
727 assert!(deserialize_signature("Not valid json.").is_err());
728 assert!(deserialize_signature("\"Not an actual signature.\"").is_err());
729 assert!(deserialize_signature("\"abc123\"").is_err());
731 }
732
733 #[test]
734 fn sign_prehashed_works() {
735 let (pair, _, _) = Pair::generate_with_phrase(Some("password"));
736
737 let msg = [0u8; 32];
739 let sig1 = pair.sign_prehashed(&msg);
740 assert!(
741 is_signature_normalized(&sig1.0),
742 "sign_prehashed should always produce a low-S signature"
743 );
744
745 let sig1_again = pair.sign_prehashed(&msg);
747 assert_eq!(sig1, sig1_again, "sign_prehashed should be deterministic");
748
749 let sig2 = pair.sign(&msg);
751 assert_ne!(sig1, sig2);
752
753 let msg = b"this should be hashed";
755 let sig1 = pair.sign_prehashed(&sp_crypto_hashing::blake2_256(msg));
756 let sig2 = pair.sign(msg);
757 assert_eq!(sig1, sig2);
758 }
759
760 #[test]
761 fn verify_prehashed_works() {
762 let (pair, _, _) = Pair::generate_with_phrase(Some("password"));
763
764 let msg = sp_crypto_hashing::blake2_256(b"this should be hashed");
766 let sig = pair.sign_prehashed(&msg);
767 assert!(Pair::verify_prehashed(&sig, &msg, &pair.public()));
768
769 let msg = sp_crypto_hashing::blake2_256(b"this is a different message");
771 assert!(!Pair::verify_prehashed(&sig, &msg, &pair.public()));
772 }
773
774 #[test]
775 fn recover_prehashed_works() {
776 let (pair, _, _) = Pair::generate_with_phrase(Some("password"));
777
778 let msg = sp_crypto_hashing::blake2_256(b"this should be hashed");
780 let sig = pair.sign_prehashed(&msg);
781 let key = sig.recover_prehashed(&msg).unwrap();
782 assert_eq!(pair.public(), key);
783
784 assert!(Pair::verify_prehashed(&sig, &msg, &key));
786
787 let msg = sp_crypto_hashing::blake2_256(b"this is a different message");
789 let key = sig.recover_prehashed(&msg).unwrap();
790 assert_ne!(pair.public(), key);
791 }
792
793 #[test]
794 fn good_proof_of_possession_should_work_bad_proof_of_possession_should_fail() {
795 let owner = b"owner";
796 let not_owner = b"not owner";
797 let mut pair = Pair::from_seed(b"12345678901234567890123456789012");
798 let other_pair = Pair::from_seed(b"23456789012345678901234567890123");
799 let proof_of_possession = pair.generate_proof_of_possession(owner);
800 assert!(Pair::verify_proof_of_possession(owner, &proof_of_possession, &pair.public()));
801 assert_eq!(
802 Pair::verify_proof_of_possession(owner, &proof_of_possession, &other_pair.public()),
803 false
804 );
805 assert!(!Pair::verify_proof_of_possession(not_owner, &proof_of_possession, &pair.public()));
806 }
807
808 #[test]
809 fn is_signature_normalized_accepts_low_s() {
810 let pair = Pair::from_seed(b"12345678901234567890123456789012");
812 let msg = sp_crypto_hashing::blake2_256(b"low-s test");
813 let sig = pair.sign_prehashed(&msg);
814 assert!(is_signature_normalized(&sig.0));
815 }
816
817 #[test]
818 fn is_signature_normalized_rejects_high_s() {
819 let pair = Pair::from_seed(b"12345678901234567890123456789012");
821 let msg = sp_crypto_hashing::blake2_256(b"high-s test");
822 let sig = pair.sign_prehashed(&msg);
823
824 let order: [u8; 32] = [
825 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
826 0xff, 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, 0xbf, 0xd2, 0x5e, 0x8c,
827 0xd0, 0x36, 0x41, 0x41,
828 ];
829
830 let s_bytes: [u8; 32] = sig.0[32..64].try_into().unwrap();
831 let mut s_prime = [0u8; 32];
832 let mut borrow = 0i16;
833 for i in (0..32).rev() {
834 let diff = order[i] as i16 - s_bytes[i] as i16 - borrow;
835 if diff < 0 {
836 s_prime[i] = (diff + 256) as u8;
837 borrow = 1;
838 } else {
839 s_prime[i] = diff as u8;
840 borrow = 0;
841 }
842 }
843
844 let mut high_s_sig = [0u8; 65];
845 high_s_sig[0..32].copy_from_slice(&sig.0[0..32]);
846 high_s_sig[32..64].copy_from_slice(&s_prime);
847 high_s_sig[64] = sig.0[64] ^ 1;
848 assert!(!is_signature_normalized(&high_s_sig));
849 }
850
851 #[test]
852 fn sign_prehashed_produces_low_s() {
853 for i in 1..21u8 {
854 let seed = [i; 32];
855 let pair = Pair::from_seed(&seed);
856 let msg = sp_crypto_hashing::blake2_256(&[i]);
857 let sig = pair.sign_prehashed(&msg);
858 assert!(
859 is_signature_normalized(&sig.0),
860 "sign_prehashed produced high-S for seed {}",
861 i
862 );
863 }
864 }
865
866 #[test]
867 fn malleable_signature_is_rejected_by_normalization_check() {
868 let order: [u8; 32] = [
869 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
870 0xff, 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, 0xbf, 0xd2, 0x5e, 0x8c,
871 0xd0, 0x36, 0x41, 0x41,
872 ];
873
874 let pair = Pair::from_seed(b"12345678901234567890123456789012");
875 let msg = sp_crypto_hashing::blake2_256(b"malleable test");
876 let sig = pair.sign_prehashed(&msg);
877
878 assert!(is_signature_normalized(&sig.0));
880
881 let s_bytes: [u8; 32] = sig.0[32..64].try_into().unwrap();
882 let mut s_prime = [0u8; 32];
883 let mut borrow = 0i16;
884 for i in (0..32).rev() {
885 let diff = order[i] as i16 - s_bytes[i] as i16 - borrow;
886 if diff < 0 {
887 s_prime[i] = (diff + 256) as u8;
888 borrow = 1;
889 } else {
890 s_prime[i] = diff as u8;
891 borrow = 0;
892 }
893 }
894
895 let mut malleable_sig_bytes = [0u8; 65];
896 malleable_sig_bytes[0..32].copy_from_slice(&sig.0[0..32]);
897 malleable_sig_bytes[32..64].copy_from_slice(&s_prime);
898 malleable_sig_bytes[64] = sig.0[64] ^ 1;
899
900 assert!(
902 !is_signature_normalized(&malleable_sig_bytes),
903 "malleable signature should be rejected as high-S"
904 );
905
906 let malleable_sig = Signature::from_raw(malleable_sig_bytes);
909 assert!(Pair::verify_prehashed(&malleable_sig, &msg, &pair.public()));
910 }
911}