referrerpolicy=no-referrer-when-downgrade

sp_core/
paired_crypto.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! API for using a pair of crypto schemes together.
19
20use 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/// ECDSA and BLS12-377 paired crypto scheme
32#[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	/// An identifier used to match public keys against BLS12-377 keys
42	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	/// (ECDSA,BLS12-377) key-pair pair.
58	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	/// (ECDSA,BLS12-377) public key pair.
68	pub type Public = super::Public<PUBLIC_KEY_LEN, EcdsaBls377Tag>;
69
70	/// (ECDSA,BLS12-377) signature pair.
71	pub type Signature = super::Signature<SIGNATURE_LEN, EcdsaBls377Tag>;
72
73	/// (ECDSA, (BLS12-377, BLS12-377))
74	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		/// Hashes the `message` with the specified [`Hasher`] before signing with the ECDSA secret
95		/// component.
96		///
97		/// The hasher does not affect the BLS12-377 component. This generates BLS12-377 Signature
98		/// according to IETF standard.
99		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		/// Hashes the `message` with the specified [`Hasher`] before verifying with the ECDSA
115		/// public component.
116		///
117		/// The hasher does not affect the the BLS12-377 component. This verifies whether the
118		/// BLS12-377 signature was hashed and signed according to IETF standard
119		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/// ECDSA and BLS12-381 paired crypto scheme
148#[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	/// An identifier used to match public keys against BLS12-381 keys
158	pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecb8");
159
160	/// Aggregate public key size.
161	pub const PUBLIC_KEY_LEN: usize =
162		ecdsa::PUBLIC_KEY_SERIALIZED_SIZE + bls381::PUBLIC_KEY_SERIALIZED_SIZE;
163
164	/// Aggregate signature serialized size.
165	pub const SIGNATURE_LEN: usize =
166		ecdsa::SIGNATURE_SERIALIZED_SIZE + bls381::SIGNATURE_SERIALIZED_SIZE;
167
168	/// Size of Proof Of Possession for (ECDSA, BLS12-381) type (this is one ECDSA and two BLS12-381
169	/// signature)
170	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	/// (ECDSA,BLS12-381) key-pair pair.
179	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	/// (ECDSA,BLS12-381) public key pair.
189	pub type Public = super::Public<PUBLIC_KEY_LEN, EcdsaBls381Tag>;
190
191	/// (ECDSA,BLS12-381) signature pair.
192	pub type Signature = super::Signature<SIGNATURE_LEN, EcdsaBls381Tag>;
193
194	/// (ECDSA, (BLS12-381, BLS12-381))
195	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		/// Hashes the `message` with the specified [`Hasher`] before signing with the ECDSA secret
216		/// component.
217		///
218		/// The hasher does not affect the BLS12-381 component. This generates BLS12-381 Signature
219		/// according to IETF standard.
220		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		/// Hashes the `message` with the specified [`Hasher`] before verifying with the ECDSA
236		/// public component.
237		///
238		/// The hasher does not affect the the BLS12-381 component. This verifies whether the
239		/// BLS12-381 signature was hashed and signed according to IETF standard
240		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
268/// Secure seed length.
269///
270/// Currently only supporting sub-schemes whose seed is a 32-bytes array.
271const SECURE_SEED_LEN: usize = 32;
272
273/// A secret seed.
274///
275/// It's not called a "secret key" because ring doesn't expose the secret keys
276/// of the key pair (yeah, dumb); as such we're forced to remember the seed manually if we
277/// will need it later (such as for HDKD).
278type Seed = [u8; SECURE_SEED_LEN];
279
280#[doc(hidden)]
281pub trait PairedCryptoSubTagBound {}
282#[doc(hidden)]
283pub struct PairedCryptoTag;
284
285/// A public key.
286pub 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
309/// A pair of signatures of different types
310pub type Signature<const LEFT_PLUS_RIGHT_LEN: usize, SubTag> =
311	SignatureBytes<LEFT_PLUS_RIGHT_LEN, (PairedCryptoTag, SubTag)>;
312
313/// A pair of proof of possession of different types
314pub type ProofOfPossession<const LEFT_PLUS_RIGHT_LEN: usize, SubTag> =
315	SignatureBytes<LEFT_PLUS_RIGHT_LEN, (PairedCryptoTag, SubTag)>;
316
317/// A key pair.
318pub 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
331///Implementation of Clone for PairedCrypto
332impl<
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
346///Implementation of keypair for paired cryptographic keys
347impl<
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	/// Derive a child key from a series of given junctions.
378	///
379	/// Note: if the `LeftPair` and `RightPair` crypto schemes differ in
380	/// seed derivation, `derive` will drop the seed in the return.
381	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	/// Get the seed/secret key for each key and then concatenate them.
434	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
474/// This requires that the proof_of_possession of LEFT is of LeftPair::Signature.
475/// This is the case for current implemented cases but does not
476/// holds in general.
477impl<
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// Test set exercising the (ECDSA,BLS12-377) implementation
525#[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		// we are using hash-to-field so this is not going to work
580		// assert_eq!(pair.seed(), seed);
581		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		// Signature is 177 bytes, hexify * 2 + 2 quote charsy
729		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		// Poorly-sized
742		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}