From 56e55d0c5a1c9cc872b7d6dc1ccd9b14955421e6 Mon Sep 17 00:00:00 2001 From: Skalman Date: Thu, 3 Aug 2023 14:52:16 +0200 Subject: [PATCH 01/13] First definition for pair public keys --- primitives/core/src/lib.rs | 1 + primitives/core/src/paired_crypto.rs | 81 ++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 primitives/core/src/paired_crypto.rs diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index da3b438190954..91851087062ce 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -57,6 +57,7 @@ pub use paste; #[cfg(feature = "bls-experimental")] pub mod bls; +pub mod paired_crypto; pub mod defer; pub mod ecdsa; pub mod ed25519; diff --git a/primitives/core/src/paired_crypto.rs b/primitives/core/src/paired_crypto.rs new file mode 100644 index 0000000000000..e999860336e6b --- /dev/null +++ b/primitives/core/src/paired_crypto.rs @@ -0,0 +1,81 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the Licenseff is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! API for using a pair of crypto schemes together. + +#[cfg(feature = "std")] +use crate::crypto::Ss58Codec; +use crate::crypto::{ByteArray, CryptoType, Derive, Public as TraitPublic, UncheckedFrom}; +#[cfg(feature = "full_crypto")] +use crate::crypto::{DeriveError, DeriveJunction, Pair as TraitPair, SecretStringError}; + +#[cfg(feature = "full_crypto")] +use sp_std::vec::Vec; + +use codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; +#[cfg(feature = "std")] +use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; + +use sp_runtime_interface::pass_by::PassByInner; +use sp_std::{convert::TryFrom, marker::PhantomData, ops::Deref}; + +/// ECDSA and BLS-377 specialized types +pub mod ecdsa_n_bls377 { + use crate::crypto::{CryptoTypeId}; + use crate::{ecdsa, ed25519}; + + /// An identifier used to match public keys against BLS12-377 keys + pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecb7"); + + /// BLS12-377 key pair. + #[cfg(feature = "full_crypto")] + //pub type Pair = super::Pair; + /// BLS12-377 public key. + pub type Public = super::Public; + // /// BLS12-377 signature. + //pub type Signature = super::Signature; + + // impl super::HardJunctionId for TinyBLS377 { + // const ID: &'static str = "BLS12377HDKD"; + // } +} + +/// A secret seed. +/// +/// It's not called a "secret key" because ring doesn't expose the secret keys +/// of the key pair (yeah, dumb); as such we're forced to remember the seed manually if we +/// will need it later (such as for HDKD). +#[cfg(feature = "full_crypto")] +//type Seed = [u8; SECRET_KEY_SERIALIZED_SIZE]; + +/// A public key. +#[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq, PartialOrd, Ord)] +#[scale_info(skip_type_params(T))] +pub struct Public { + left_public : LeftPublic, + right_public: RightPublic, +} + +#[cfg(feature = "full_crypto")] +impl sp_std::hash::Hash for Public { + fn hash(&self, state: &mut H) { + self.left_public.hash(state); + self.right_public.hash(state); + } +} + From fb3c187ae57ff4d5fdd552b0364bd3bee35104ae Mon Sep 17 00:00:00 2001 From: Skalman Date: Thu, 3 Aug 2023 16:35:02 +0200 Subject: [PATCH 02/13] Two example of implementation of pair for demonestration --- primitives/core/src/paired_crypto.rs | 44 +++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/primitives/core/src/paired_crypto.rs b/primitives/core/src/paired_crypto.rs index e999860336e6b..0dbab1cd960f1 100644 --- a/primitives/core/src/paired_crypto.rs +++ b/primitives/core/src/paired_crypto.rs @@ -63,19 +63,47 @@ pub mod ecdsa_n_bls377 { #[cfg(feature = "full_crypto")] //type Seed = [u8; SECRET_KEY_SERIALIZED_SIZE]; +pub trait PublicKeyBound: TraitPublic + sp_std::hash::Hash + ByteArray {} /// A public key. #[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq, PartialOrd, Ord)] #[scale_info(skip_type_params(T))] -pub struct Public { +pub struct PublicWithInner { + inner: [u8; LEFT_PLUS_RIGHT_SIZE], + _phantom: PhantomData (LeftPublic, RightPublic)>, +} + +pub struct Public { left_public : LeftPublic, right_public: RightPublic, } -#[cfg(feature = "full_crypto")] -impl sp_std::hash::Hash for Public { - fn hash(&self, state: &mut H) { - self.left_public.hash(state); - self.right_public.hash(state); - } -} +// #[cfg(feature = "full_crypto")] +// impl sp_std::hash::Hash for Public { +// fn hash(&self, state: &mut H) { +// self.left_public.hash(state); +// self.right_public.hash(state); +// } +// } + +// impl ByteArray for Public { +// const LEN: usize = T1::LEN + T2::LEN; +// } + +// impl TryFrom<&[u8]> for Public { +// type Error = (); + +// fn try_from(data: &[u8]) -> Result { +// // if data.len() != PUBLIC_KEY_SERIALIZED_SIZE { +// // return Err(()) +// // } +// // let mut r = [0u8; PUBLIC_KEY_SERIALIZED_SIZE]; +// // r.copy_from_slice(data); +// // Ok(Self::unchecked_from(r)) +// } +// } +// impl AsMut<[u8]> for Public { +// fn as_mut(&mut self) -> &mut [u8] { +// &mut self.inner[..] +// } +// } From 2a6283a75c926929363f2695fb2781afe62c2b5b Mon Sep 17 00:00:00 2001 From: Skalman Date: Mon, 14 Aug 2023 10:15:06 -0400 Subject: [PATCH 03/13] - implement paired crypto `Public` as tuple of two `Public`s - unsucessfuly try to implement ByteArray for paired crypto Public --- primitives/core/src/paired_crypto.rs | 79 +++++++++++++++++----------- 1 file changed, 47 insertions(+), 32 deletions(-) diff --git a/primitives/core/src/paired_crypto.rs b/primitives/core/src/paired_crypto.rs index 0dbab1cd960f1..59fb3bbf0aa36 100644 --- a/primitives/core/src/paired_crypto.rs +++ b/primitives/core/src/paired_crypto.rs @@ -34,6 +34,7 @@ use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use sp_runtime_interface::pass_by::PassByInner; use sp_std::{convert::TryFrom, marker::PhantomData, ops::Deref}; + /// ECDSA and BLS-377 specialized types pub mod ecdsa_n_bls377 { use crate::crypto::{CryptoTypeId}; @@ -46,7 +47,7 @@ pub mod ecdsa_n_bls377 { #[cfg(feature = "full_crypto")] //pub type Pair = super::Pair; /// BLS12-377 public key. - pub type Public = super::Public; + pub type Public = super::Public; // /// BLS12-377 signature. //pub type Signature = super::Signature; @@ -63,47 +64,61 @@ pub mod ecdsa_n_bls377 { #[cfg(feature = "full_crypto")] //type Seed = [u8; SECRET_KEY_SERIALIZED_SIZE]; -pub trait PublicKeyBound: TraitPublic + sp_std::hash::Hash + ByteArray {} +pub trait PublicKeyBound: TraitPublic + sp_std::hash::Hash + ByteArray {} /// A public key. #[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq, PartialOrd, Ord)] #[scale_info(skip_type_params(T))] -pub struct PublicWithInner { - inner: [u8; LEFT_PLUS_RIGHT_SIZE], - _phantom: PhantomData (LeftPublic, RightPublic)>, +pub struct Public (LeftPublic, RightPublic); + +#[cfg(feature = "full_crypto")] +impl, RightPublic: PublicKeyBound + UncheckedFrom<[u8; RIGHT_LEN]>, const LEFT_LEN: usize, const RIGHT_LEN: usize> sp_std::hash::Hash for Public { + fn hash(&self, state: &mut H) { + self.0.hash(state); + self.1.hash(state); + } } -pub struct Public { - left_public : LeftPublic, - right_public: RightPublic, +impl ByteArray for Public where for<'a> Public: TryFrom<&'a [u8], Error = ()> + AsRef<[u8]> + AsMut<[u8]> { + const LEN: usize = LeftPublic::LEN + RightPublic::LEN; } -// #[cfg(feature = "full_crypto")] -// impl sp_std::hash::Hash for Public { -// fn hash(&self, state: &mut H) { -// self.left_public.hash(state); -// self.right_public.hash(state); -// } -// } +impl<'a,LeftPublic: PublicKeyBound + UncheckedFrom<[u8; LEFT_LEN]>, RightPublic: PublicKeyBound + UncheckedFrom<[u8; RIGHT_LEN]>, const LEFT_LEN: usize, const RIGHT_LEN: usize> TryFrom<&'a[u8]> for Public { + type Error = (); + + fn try_from(data: &[u8]) -> Result { + if data.len() != LEFT_LEN + RIGHT_LEN { + return Err(()) + } + + let mut r0 = [0u8; LEFT_LEN]; + let mut r1 = [0u8; RIGHT_LEN]; + r0.copy_from_slice(&data[0..LEFT_LEN]); + r1.copy_from_slice(&data[LEFT_LEN..RIGHT_LEN]); + Ok(Self(LeftPublic::unchecked_from(r0),RightPublic::unchecked_from(r1))) + } +} -// impl ByteArray for Public { -// const LEN: usize = T1::LEN + T2::LEN; +// impl AsMut<[u8]> for Public { +// fn as_mut(&mut self) -> &mut [u8] { +// &mut [self.0.as_mut(), self.1.as_mut()].concat() +// } // } -// impl TryFrom<&[u8]> for Public { -// type Error = (); - -// fn try_from(data: &[u8]) -> Result { -// // if data.len() != PUBLIC_KEY_SERIALIZED_SIZE { -// // return Err(()) -// // } -// // let mut r = [0u8; PUBLIC_KEY_SERIALIZED_SIZE]; -// // r.copy_from_slice(data); -// // Ok(Self::unchecked_from(r)) -// } +// impl AsRef<[u8; RIGHT_PLUS_LEFT_LEN]> for Public where for<'a> Public: TryFrom<&'a [u8], Error = ()> { +// fn as_ref(&self) -> &[u8; RIGHT_PLUS_LEFT_LEN] { +// let mut r = [0u8; RIGHT_PLUS_LEFT_LEN]; +// r.copy_from_slice(self.0.as_ref()); +// r[LeftPublic::LEN..].copy_from_slice(self.1.as_ref()); +// &r +// } // } -// impl AsMut<[u8]> for Public { -// fn as_mut(&mut self) -> &mut [u8] { -// &mut self.inner[..] -// } +// impl AsRef<[u8]> for Public { +// fn as_ref(&self) -> &[u8] { +// //let mut r : Vec = vec![0u8; LEFT_LEN + RIGHT_LEN]; +// //r.copy_from_slice(self.0.as_ref(), LeftPublic::LEN); +// //r[LeftPublic::LEN..].copy_from_slice(self.1.as_ref(), RightPublic::LEN); +// let mut r :Vec = [self.0.as_ref(), self.1.as_ref()].concat(); +// &r[..] +// } // } From 1fbcbc0243a853aedbd19b48800d033a3b5662f0 Mon Sep 17 00:00:00 2001 From: Skalman Date: Mon, 21 Aug 2023 09:12:50 -0400 Subject: [PATCH 04/13] keep both public key object and their continous serialization in paired crypto object in favor of avoiding copy --- primitives/core/src/paired_crypto.rs | 98 +++++++++++++++------------- 1 file changed, 54 insertions(+), 44 deletions(-) diff --git a/primitives/core/src/paired_crypto.rs b/primitives/core/src/paired_crypto.rs index 59fb3bbf0aa36..3ae113d9f3a4b 100644 --- a/primitives/core/src/paired_crypto.rs +++ b/primitives/core/src/paired_crypto.rs @@ -37,7 +37,7 @@ use sp_std::{convert::TryFrom, marker::PhantomData, ops::Deref}; /// ECDSA and BLS-377 specialized types pub mod ecdsa_n_bls377 { - use crate::crypto::{CryptoTypeId}; + use crate::crypto::{CryptoTypeId}; use crate::{ecdsa, ed25519}; /// An identifier used to match public keys against BLS12-377 keys @@ -47,7 +47,7 @@ pub mod ecdsa_n_bls377 { #[cfg(feature = "full_crypto")] //pub type Pair = super::Pair; /// BLS12-377 public key. - pub type Public = super::Public; + pub type Public = super::Public; // /// BLS12-377 signature. //pub type Signature = super::Signature; @@ -64,61 +64,71 @@ pub mod ecdsa_n_bls377 { #[cfg(feature = "full_crypto")] //type Seed = [u8; SECRET_KEY_SERIALIZED_SIZE]; -pub trait PublicKeyBound: TraitPublic + sp_std::hash::Hash + ByteArray {} +pub trait PublicKeyBound: TraitPublic + sp_std::hash::Hash + ByteArray + for<'a> TryFrom<&'a[u8]> {} /// A public key. #[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq, PartialOrd, Ord)] #[scale_info(skip_type_params(T))] -pub struct Public (LeftPublic, RightPublic); +pub struct Public { + left: LeftPublic, + right: RightPublic, + inner: [u8; LEFT_PLUS_RIGHT_LEN], +} + +// We essentially could implement this instead of storing left and right but we are going to end up copying left and right. +// impl Public { +// inline fn left<'a>(&self)-> &'a LeftPublic { +// &LeftPublic::try_from(&self.inner[0..LeftPublic::LEN]).unwrap() +// } + +// fn right<'a>(&self)-> &'a RightPublic { +// &RightPublic::try_from(&self.inner[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN]).unwrap() +// } + + +// } #[cfg(feature = "full_crypto")] -impl, RightPublic: PublicKeyBound + UncheckedFrom<[u8; RIGHT_LEN]>, const LEFT_LEN: usize, const RIGHT_LEN: usize> sp_std::hash::Hash for Public { - fn hash(&self, state: &mut H) { - self.0.hash(state); - self.1.hash(state); +impl sp_std::hash::Hash for Public { + fn hash(&self, state: &mut H) { + self.left.hash(state); + self.right.hash(state); } } -impl ByteArray for Public where for<'a> Public: TryFrom<&'a [u8], Error = ()> + AsRef<[u8]> + AsMut<[u8]> { - const LEN: usize = LeftPublic::LEN + RightPublic::LEN; +impl ByteArray for Public { + const LEN: usize = LEFT_PLUS_RIGHT_LEN; } -impl<'a,LeftPublic: PublicKeyBound + UncheckedFrom<[u8; LEFT_LEN]>, RightPublic: PublicKeyBound + UncheckedFrom<[u8; RIGHT_LEN]>, const LEFT_LEN: usize, const RIGHT_LEN: usize> TryFrom<&'a[u8]> for Public { - type Error = (); +impl<'a,LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> TryFrom<&'a[u8]> for Public { + type Error = (); + + fn try_from(data: &[u8]) -> Result { + if data.len() != LEFT_PLUS_RIGHT_LEN { + return Err(()) + } + let mut left : LeftPublic = data[0..LeftPublic::LEN].try_into().unwrap(); + let mut right : RightPublic = data[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into().unwrap(); - fn try_from(data: &[u8]) -> Result { - if data.len() != LEFT_LEN + RIGHT_LEN { - return Err(()) - } + let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; + Ok(Public { left, right, inner }) + + } +} - let mut r0 = [0u8; LEFT_LEN]; - let mut r1 = [0u8; RIGHT_LEN]; - r0.copy_from_slice(&data[0..LEFT_LEN]); - r1.copy_from_slice(&data[LEFT_LEN..RIGHT_LEN]); - Ok(Self(LeftPublic::unchecked_from(r0),RightPublic::unchecked_from(r1))) +impl AsMut<[u8]> for Public { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.inner[..] } } -// impl AsMut<[u8]> for Public { -// fn as_mut(&mut self) -> &mut [u8] { -// &mut [self.0.as_mut(), self.1.as_mut()].concat() -// } -// } - -// impl AsRef<[u8; RIGHT_PLUS_LEFT_LEN]> for Public where for<'a> Public: TryFrom<&'a [u8], Error = ()> { -// fn as_ref(&self) -> &[u8; RIGHT_PLUS_LEFT_LEN] { -// let mut r = [0u8; RIGHT_PLUS_LEFT_LEN]; -// r.copy_from_slice(self.0.as_ref()); -// r[LeftPublic::LEN..].copy_from_slice(self.1.as_ref()); -// &r -// } -// } +impl AsRef<[u8; LEFT_PLUS_RIGHT_LEN]> for Public { + fn as_ref(&self) -> &[u8; LEFT_PLUS_RIGHT_LEN] { + &self.inner + } +} -// impl AsRef<[u8]> for Public { -// fn as_ref(&self) -> &[u8] { -// //let mut r : Vec = vec![0u8; LEFT_LEN + RIGHT_LEN]; -// //r.copy_from_slice(self.0.as_ref(), LeftPublic::LEN); -// //r[LeftPublic::LEN..].copy_from_slice(self.1.as_ref(), RightPublic::LEN); -// let mut r :Vec = [self.0.as_ref(), self.1.as_ref()].concat(); -// &r[..] -// } -// } +impl AsRef<[u8]> for Public { + fn as_ref(&self) -> &[u8] { + &self.inner[..] + } +} From cf138122c12f6084f7ae8f154d5b28043b11bdca Mon Sep 17 00:00:00 2001 From: Skalman Date: Mon, 21 Aug 2023 18:21:10 +0200 Subject: [PATCH 05/13] implement PassBy and From for paired_crypto --- primitives/core/src/paired_crypto.rs | 35 +++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/primitives/core/src/paired_crypto.rs b/primitives/core/src/paired_crypto.rs index 3ae113d9f3a4b..e2f1081c8393b 100644 --- a/primitives/core/src/paired_crypto.rs +++ b/primitives/core/src/paired_crypto.rs @@ -64,7 +64,8 @@ pub mod ecdsa_n_bls377 { #[cfg(feature = "full_crypto")] //type Seed = [u8; SECRET_KEY_SERIALIZED_SIZE]; -pub trait PublicKeyBound: TraitPublic + sp_std::hash::Hash + ByteArray + for<'a> TryFrom<&'a[u8]> {} +//pub trait Public: ByteArray + Derive + CryptoType + PartialEq + Eq + Clone + Send + Sync {} +pub trait PublicKeyBound: TraitPublic + sp_std::hash::Hash + ByteArray + for<'a> TryFrom<&'a[u8]> {} /// A public key. #[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq, PartialOrd, Ord)] #[scale_info(skip_type_params(T))] @@ -132,3 +133,35 @@ impl PassByInner for Public { + type Inner = [u8; LEFT_PLUS_RIGHT_LEN]; + + fn into_inner(self) -> Self::Inner { + self.inner + } + + fn inner(&self) -> &Self::Inner { + &self.inner + } + + fn from_inner(inner: Self::Inner) -> Self { + let mut left : LeftPublic = inner[0..LeftPublic::LEN].try_into().unwrap(); + let mut right : RightPublic = inner[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into().unwrap(); + + Self { left, right, inner } + } +} + +#[cfg(feature = "full_crypto")] +impl From> for Public where Pair : TraitPair>, +{ + fn from(x: Pair) -> Self { + x.public() + } +} + +/// A key pair. +#[cfg(feature = "full_crypto")] +#[derive(Clone)] +pub struct Pair(LeftPair, RightPair); From a4f9dfe8bb52d74ae82f3e67606bf4e4de3c4bf6 Mon Sep 17 00:00:00 2001 From: Skalman Date: Tue, 22 Aug 2023 16:58:16 -0400 Subject: [PATCH 06/13] implement rest of aux traits for `paired_crypto::Public` implement some of aux traits for `paired_crypto::Signature` --- primitives/core/src/paired_crypto.rs | 153 ++++++++++++++++++++++++++- 1 file changed, 149 insertions(+), 4 deletions(-) diff --git a/primitives/core/src/paired_crypto.rs b/primitives/core/src/paired_crypto.rs index e2f1081c8393b..5e384eb1155a2 100644 --- a/primitives/core/src/paired_crypto.rs +++ b/primitives/core/src/paired_crypto.rs @@ -45,12 +45,17 @@ pub mod ecdsa_n_bls377 { /// BLS12-377 key pair. #[cfg(feature = "full_crypto")] - //pub type Pair = super::Pair; + pub type Pair = super::Pair; /// BLS12-377 public key. pub type Public = super::Public; // /// BLS12-377 signature. //pub type Signature = super::Signature; + // impl super::CryptoType for Public + // { + // #[cfg(feature = "full_crypto")] + // type Pair = Pair; + // } // impl super::HardJunctionId for TinyBLS377 { // const ID: &'static str = "BLS12377HDKD"; // } @@ -65,7 +70,10 @@ pub mod ecdsa_n_bls377 { //type Seed = [u8; SECRET_KEY_SERIALIZED_SIZE]; //pub trait Public: ByteArray + Derive + CryptoType + PartialEq + Eq + Clone + Send + Sync {} -pub trait PublicKeyBound: TraitPublic + sp_std::hash::Hash + ByteArray + for<'a> TryFrom<&'a[u8]> {} +pub trait PublicKeyBound: TraitPublic + Sized + Derive + sp_std::hash::Hash + ByteArray + for<'a> TryFrom<&'a[u8]> + AsMut<[u8]> + CryptoType {} + +impl TryFrom<&'a[u8]> + AsMut<[u8]> + CryptoType> PublicKeyBound for PublicKeyTrait {} + /// A public key. #[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq, PartialOrd, Ord)] #[scale_info(skip_type_params(T))] @@ -107,7 +115,7 @@ impl<'a,LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS if data.len() != LEFT_PLUS_RIGHT_LEN { return Err(()) } - let mut left : LeftPublic = data[0..LeftPublic::LEN].try_into().unwrap(); + let mut left : LeftPublic = data[0..LeftPublic::LEN].try_into().unwrap(); let mut right : RightPublic = data[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into().unwrap(); let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; @@ -155,13 +163,150 @@ impl From> for Public where Pair : TraitPair>, -{ + { fn from(x: Pair) -> Self { x.public() } } +impl UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]> for Public { + fn unchecked_from(data: [u8; LEFT_PLUS_RIGHT_LEN]) -> Self { + let mut left : LeftPublic = data[0..LeftPublic::LEN].try_into().unwrap(); + let mut right : RightPublic = data[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into().unwrap(); + + let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; + Public { left, right, inner } + + } +} + +#[cfg(feature = "std")] +impl std::str::FromStr for Public where Public : CryptoType { + type Err = crate::crypto::PublicError; + + fn from_str(s: &str) -> Result { + ::from_ss58check(s) + } +} + +#[cfg(feature = "std")] +impl std::fmt::Display for Public where Public : CryptoType { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", self.to_ss58check()) + } +} + +#[cfg(feature = "std")] +impl sp_std::fmt::Debug for Public where Public : CryptoType, [u8;LEFT_PLUS_RIGHT_LEN]: crate::hexdisplay::AsBytesRef { + fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + let s = self.to_ss58check(); + write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.inner), &s[0..8]) + } +} + +#[cfg(not(feature = "std"))] +impl_sp_std::fmt::Debug for Public { + fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + + Ok(()) + } +} + +#[cfg(feature = "std")] +impl Serialize for Public where Public : CryptoType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&self.to_ss58check()) + + } +} + +#[cfg(feature = "std")] +impl<'de, LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> Deserialize<'de> for Public where Public : CryptoType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Public::from_ss58check(&String::deserialize(deserializer)?) + .map_err(|e| de::Error::custom(format!("{:?}", e))) + + } +} + +impl TraitPublic for Public where Public : CryptoType {} + +impl Derive for Public {} + +#[cfg(not(feature = "full_crypto"))] +impl CryptoType for Public +{} + +//pub trait Public: ByteArray + Derive + CryptoType + PartialEq + Eq + Clone + Send + Sync {} +pub trait SignatureBound: sp_std::hash::Hash + for<'a> TryFrom<&'a[u8]> {} + +/// A pair of signatures of different types +#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq)] +#[scale_info(skip_type_params(T))] +pub struct Signature { + left: LeftSignature, + right: RightSignature, + inner: [u8; LEFT_PLUS_RIGHT_LEN], +} + +#[cfg(feature = "full_crypto")] +impl sp_std::hash::Hash for Signature { + fn hash(&self, state: &mut H) { + self.left.hash(state); + self.right.hash(state); + } +} + +impl<'a,LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_LEN: usize, const RIGHT_LEN: usize, const LEFT_PLUS_RIGHT_LEN: usize> TryFrom<&'a[u8]> for Signature { + type Error = (); + + fn try_from(data: &[u8]) -> Result { + if data.len() != LEFT_PLUS_RIGHT_LEN { + return Err(()) + } + let Ok(mut left) = data[0..LEFT_LEN].try_into() else { panic!("invalid signature") }; + let Ok(mut right) = data[LEFT_LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { panic!("invalid signature") }; + + let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; + Ok(Signature { left, right, inner }) + + } +} + +impl AsMut<[u8]> for Signature { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.inner[..] + } +} + +impl AsRef<[u8; LEFT_PLUS_RIGHT_LEN]> for Signature { + fn as_ref(&self) -> &[u8; LEFT_PLUS_RIGHT_LEN] { + &self.inner + } +} + +impl AsRef<[u8]> for Signature { + fn as_ref(&self) -> &[u8] { + &self.inner[..] + } +} + // serializer.serialize_str(&array_bytes::bytes2hex("", self)) + + // let signature_hex = array_bytes::hex2bytes(&String::deserialize(deserializer)?) + // .map_err(|e| de::Error::custom(format!("{:?}", e)))?; + // Signature::try_from(signature_hex.as_ref()) + // .map_err(|e| de::Error::custom(format!("{:?}", e))) + /// A key pair. #[cfg(feature = "full_crypto")] #[derive(Clone)] pub struct Pair(LeftPair, RightPair); + + + From f4b9ae6bd4436dd0625484ae5d49525f9c2d7512 Mon Sep 17 00:00:00 2001 From: Skalman Date: Tue, 29 Aug 2023 05:00:05 -0400 Subject: [PATCH 07/13] Attempt to implement trait `Pair` for `pair_cyrpto::Pair` --- primitives/core/src/paired_crypto.rs | 198 ++++++++++++++++++++++++--- 1 file changed, 180 insertions(+), 18 deletions(-) diff --git a/primitives/core/src/paired_crypto.rs b/primitives/core/src/paired_crypto.rs index 5e384eb1155a2..2f6838db86949 100644 --- a/primitives/core/src/paired_crypto.rs +++ b/primitives/core/src/paired_crypto.rs @@ -34,7 +34,6 @@ use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use sp_runtime_interface::pass_by::PassByInner; use sp_std::{convert::TryFrom, marker::PhantomData, ops::Deref}; - /// ECDSA and BLS-377 specialized types pub mod ecdsa_n_bls377 { use crate::crypto::{CryptoTypeId}; @@ -59,6 +58,12 @@ pub mod ecdsa_n_bls377 { // impl super::HardJunctionId for TinyBLS377 { // const ID: &'static str = "BLS12377HDKD"; // } + +// impl CryptoType for Signature { +// #[cfg(feature = "full_crypto")] +// type Pair = Pair; +// } + } /// A secret seed. @@ -67,7 +72,7 @@ pub mod ecdsa_n_bls377 { /// of the key pair (yeah, dumb); as such we're forced to remember the seed manually if we /// will need it later (such as for HDKD). #[cfg(feature = "full_crypto")] -//type Seed = [u8; SECRET_KEY_SERIALIZED_SIZE]; +type Seed = [u8; {LEFT_PLUS_RIGHT_LEN}]; //pub trait Public: ByteArray + Derive + CryptoType + PartialEq + Eq + Clone + Send + Sync {} pub trait PublicKeyBound: TraitPublic + Sized + Derive + sp_std::hash::Hash + ByteArray + for<'a> TryFrom<&'a[u8]> + AsMut<[u8]> + CryptoType {} @@ -176,8 +181,8 @@ impl_sp_std::fmt::Debug for Public { +impl sp_std::fmt::Debug for Public { fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { Ok(()) @@ -249,29 +254,35 @@ pub trait SignatureBound: sp_std::hash::Hash + for<'a> TryFrom<&'a[u8]> {} /// A pair of signatures of different types #[derive(Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq)] #[scale_info(skip_type_params(T))] -pub struct Signature { +pub struct Signature { left: LeftSignature, right: RightSignature, inner: [u8; LEFT_PLUS_RIGHT_LEN], } +trait SignaturePair { + const LEFT_SIGNATURE_LEN: usize; + const RIGHT_SIGNATURE_LEN: usize; + const LEFT_PLUS_RIGHT_LEN: usize; +} + #[cfg(feature = "full_crypto")] -impl sp_std::hash::Hash for Signature { +impl sp_std::hash::Hash for Signature { fn hash(&self, state: &mut H) { self.left.hash(state); self.right.hash(state); } } -impl<'a,LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_LEN: usize, const RIGHT_LEN: usize, const LEFT_PLUS_RIGHT_LEN: usize> TryFrom<&'a[u8]> for Signature { +impl<'a,LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize> TryFrom<&'a[u8]> for Signature where Signature: SignaturePair { type Error = (); fn try_from(data: &[u8]) -> Result { if data.len() != LEFT_PLUS_RIGHT_LEN { return Err(()) } - let Ok(mut left) = data[0..LEFT_LEN].try_into() else { panic!("invalid signature") }; - let Ok(mut right) = data[LEFT_LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { panic!("invalid signature") }; + let Ok(mut left) = data[0..Self::LEFT_SIGNATURE_LEN].try_into() else { panic!("invalid signature") }; + let Ok(mut right) = data[Self::LEFT_SIGNATURE_LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { panic!("invalid signature") }; let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; Ok(Signature { left, right, inner }) @@ -279,34 +290,185 @@ impl<'a,LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEF } } -impl AsMut<[u8]> for Signature { +impl AsMut<[u8]> for Signature { fn as_mut(&mut self) -> &mut [u8] { &mut self.inner[..] } } -impl AsRef<[u8; LEFT_PLUS_RIGHT_LEN]> for Signature { +impl AsRef<[u8; LEFT_PLUS_RIGHT_LEN]> for Signature { fn as_ref(&self) -> &[u8; LEFT_PLUS_RIGHT_LEN] { &self.inner } } -impl AsRef<[u8]> for Signature { +impl AsRef<[u8]> for Signature { fn as_ref(&self) -> &[u8] { &self.inner[..] } } - // serializer.serialize_str(&array_bytes::bytes2hex("", self)) +#[cfg(feature = "std")] +impl Serialize for Signature { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&array_bytes::bytes2hex("", self)) + } +} + +#[cfg(feature = "std")] +impl<'de, LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize,> Deserialize<'de> for Signature { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let signature_hex = array_bytes::hex2bytes(&String::deserialize(deserializer)?) + .map_err(|e| de::Error::custom(format!("{:?}", e)))?; + Signature::try_from(signature_hex.as_ref()) + .map_err(|e| de::Error::custom(format!("{:?}", e))) + } +} + +impl From> for [u8; LEFT_PLUS_RIGHT_LEN] +{ + fn from(signature: Signature) -> [u8; LEFT_PLUS_RIGHT_LEN] { + signature.inner + } +} + +impl sp_std::fmt::Debug for Signature { + #[cfg(feature = "std")] + fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.inner)) + } + + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + Ok(()) + } +} + +impl UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]> for Signature where Signature: SignaturePair { + fn unchecked_from(data: [u8; LEFT_PLUS_RIGHT_LEN]) -> Self { + let mut left : LeftSignature = data[0..Self::LEFT_SIGNATURE_LEN].try_into().unwrap(); + let mut right : RightSignature = data[Self::LEFT_SIGNATURE_LEN..LEFT_PLUS_RIGHT_LEN].try_into().unwrap(); - // let signature_hex = array_bytes::hex2bytes(&String::deserialize(deserializer)?) - // .map_err(|e| de::Error::custom(format!("{:?}", e)))?; - // Signature::try_from(signature_hex.as_ref()) - // .map_err(|e| de::Error::custom(format!("{:?}", e))) + let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; + Signature { left, right, inner } + } +} /// A key pair. #[cfg(feature = "full_crypto")] #[derive(Clone)] -pub struct Pair(LeftPair, RightPair); +pub struct Pair { + left: LeftPair, + right: RightPair, + +} +trait DoublePair { + const PUBLIC_KEY_LEN: usize; + const LEFT_SIGNATURE_LEN: usize; + const RIGHT_SIGNATURE_LEN:usize; + const SIGNATURE_LEN: usize; + const LEFT_SEED_LEN: usize; + const RIGHT_SEED_LEN: usize; +} +trait HardJunctionId { + const ID: &'static str; +} + +#[cfg(feature = "full_crypto")] +impl Pair { +} + +#[cfg(feature = "full_crypto")] +impl TraitPair for Pair where + Pair: DoublePair + CryptoType, + LeftPair::Signature: SignatureBound, + RightPair::Signature: SignatureBound, +{ + type Seed = (LeftPair::Seed, RightPair::Seed); + type Public = Public::PUBLIC_KEY_LEN}>; + type Signature = Signature; + + fn from_seed_slice(seed_slice: &[u8]) -> Result { + if seed_slice.len() != Self::RIGHT_SEED_LEN + Self::LEFT_SEED_LEN { + return Err(SecretStringError::InvalidSeedLength) + } + let left = LeftPair::from_seed_slice(seed_slice[0..Self::LEFT_SEED_LEN])?; + let right = RightPair::from_seed_slice(seed_slice[Self::LEFT_SEED_LEN..Self::RIGHT_SEED_LEN + Self::LEFT_SEED_LEN])?; + Ok(Pair { left, right }) + } + + // fn derive>( + // &self, + // path: Iter, + // _seed: Option, + // ) -> Result<(Self, Option), DeriveError> { + // let mut acc: [u8; SECRET_KEY_SERIALIZED_SIZE] = + // self.0.secret.to_bytes().try_into().expect( + // "Secret key serializer returns a vector of SECRET_KEY_SERIALIZED_SIZE size", + // ); + // for j in path { + // match j { + // DeriveJunction::Soft(_cc) => return Err(DeriveError::SoftKeyInPath), + // DeriveJunction::Hard(cc) => acc = derive_hard_junction::(&acc, &cc), + // } + // } + // Ok((Self::from_seed(&acc), Some(acc))) + // } + + // fn public(&self) -> Self::Public { + // let mut raw = [0u8; PUBLIC_KEY_SERIALIZED_SIZE]; + // let pk = DoublePublicKeyScheme::into_double_public_key(&self.0).to_bytes(); + // raw.copy_from_slice(pk.as_slice()); + // Self::Public::unchecked_from(raw) + // } + + // fn sign(&self, message: &[u8]) -> Self::Signature { + // let mut mutable_self = self.clone(); + // let r: [u8; SIGNATURE_SERIALIZED_SIZE] = + // DoublePublicKeyScheme::sign(&mut mutable_self.0, &Message::new(b"", message)) + // .to_bytes() + // .try_into() + // .expect("Signature serializer returns vectors of SIGNATURE_SERIALIZED_SIZE size"); + // Self::Signature::unchecked_from(r) + // } + + // fn verify>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool { + // let pubkey_array: [u8; PUBLIC_KEY_SERIALIZED_SIZE] = + // match <[u8; PUBLIC_KEY_SERIALIZED_SIZE]>::try_from(pubkey.as_ref()) { + // Ok(pk) => pk, + // Err(_) => return false, + // }; + // let public_key = match w3f_bls::double::DoublePublicKey::::from_bytes(&pubkey_array) { + // Ok(pk) => pk, + // Err(_) => return false, + // }; + + // let sig_array = match sig.inner[..].try_into() { + // Ok(s) => s, + // Err(_) => return false, + // }; + // let sig = match w3f_bls::double::DoubleSignature::from_bytes(sig_array) { + // Ok(s) => s, + // Err(_) => return false, + // }; + + // sig.verify(&Message::new(b"", message.as_ref()), &public_key) + // } + + // /// Get the seed for this key. + // fn to_raw_vec(&self) -> Vec { + // self.0 + // .secret + // .to_bytes() + // .try_into() + // .expect("Secret key serializer returns a vector of SECRET_KEY_SERIALIZED_SIZE size") + // } +} From 4e7fb6329565cb1dca8231da766332300de74807 Mon Sep 17 00:00:00 2001 From: Skalman Date: Thu, 31 Aug 2023 10:11:56 -0400 Subject: [PATCH 08/13] - Implement trait `Pair` for `paired_crypto::Pair` - Implement a pair of seeds for paired crypto scheme. --- primitives/core/src/paired_crypto.rs | 172 ++++++++++++++++----------- 1 file changed, 105 insertions(+), 67 deletions(-) diff --git a/primitives/core/src/paired_crypto.rs b/primitives/core/src/paired_crypto.rs index 2f6838db86949..b76a7b42c0ff0 100644 --- a/primitives/core/src/paired_crypto.rs +++ b/primitives/core/src/paired_crypto.rs @@ -44,7 +44,7 @@ pub mod ecdsa_n_bls377 { /// BLS12-377 key pair. #[cfg(feature = "full_crypto")] - pub type Pair = super::Pair; + pub type Pair = super::Pair; /// BLS12-377 public key. pub type Public = super::Public; // /// BLS12-377 signature. @@ -66,14 +66,26 @@ pub mod ecdsa_n_bls377 { } +#[cfg(feature = "full_crypto")] +const SECURE_SEED_LEN: usize = 32; + +#[cfg(feature = "full_crypto")] +const DOUBLE_SEED_LEN: usize = SECURE_SEED_LEN * 2; + /// A secret seed. /// /// It's not called a "secret key" because ring doesn't expose the secret keys /// of the key pair (yeah, dumb); as such we're forced to remember the seed manually if we /// will need it later (such as for HDKD). #[cfg(feature = "full_crypto")] -type Seed = [u8; {LEFT_PLUS_RIGHT_LEN}]; +pub trait SeedBound: Default + AsRef<[u8]> + AsMut<[u8]> + Clone {} +#[cfg(feature = "full_crypto")] +pub struct Seed { + left: LeftSeed, + right: RightSeed, + inner: [u8; LEFT_PLUS_RIGHT_LEN], +} //pub trait Public: ByteArray + Derive + CryptoType + PartialEq + Eq + Clone + Send + Sync {} pub trait PublicKeyBound: TraitPublic + Sized + Derive + sp_std::hash::Hash + ByteArray + for<'a> TryFrom<&'a[u8]> + AsMut<[u8]> + CryptoType {} @@ -120,8 +132,8 @@ impl<'a,LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS if data.len() != LEFT_PLUS_RIGHT_LEN { return Err(()) } - let mut left : LeftPublic = data[0..LeftPublic::LEN].try_into().unwrap(); - let mut right : RightPublic = data[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into().unwrap(); + let mut left : LeftPublic = data[0..LeftPublic::LEN].try_into()?; + let mut right : RightPublic = data[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into()?; let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; Ok(Public { left, right, inner }) @@ -167,9 +179,9 @@ impl From> for Public where Pair : TraitPair>, +impl From> for Public where Pair : TraitPair>, { - fn from(x: Pair) -> Self { + fn from(x: Pair) -> Self { x.public() } } @@ -179,8 +191,7 @@ impl CryptoType for Public {} + //pub trait Public: ByteArray + Derive + CryptoType + PartialEq + Eq + Clone + Send + Sync {} -pub trait SignatureBound: sp_std::hash::Hash + for<'a> TryFrom<&'a[u8]> {} +pub trait SignatureBound: sp_std::hash::Hash + for<'a> TryFrom<&'a[u8]> + AsRef<[u8]> {} /// A pair of signatures of different types #[derive(Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq)] @@ -281,10 +293,13 @@ impl<'a,LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEF if data.len() != LEFT_PLUS_RIGHT_LEN { return Err(()) } - let Ok(mut left) = data[0..Self::LEFT_SIGNATURE_LEN].try_into() else { panic!("invalid signature") }; - let Ok(mut right) = data[Self::LEFT_SIGNATURE_LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { panic!("invalid signature") }; + let Ok(mut left) : Result = data[0..Self::LEFT_SIGNATURE_LEN].try_into() else { panic!("invalid signature") }; + let Ok(mut right) : Result= data[Self::LEFT_SIGNATURE_LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { panic!("invalid signature") }; + + let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; + inner.copy_from_slice(left.as_ref()); + inner[Self::LEFT_SIGNATURE_LEN..].copy_from_slice(right.as_ref()); - let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; Ok(Signature { left, right, inner }) } @@ -318,15 +333,17 @@ impl Deserialize<'de> for Signature { +impl<'de,LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize,> Deserialize<'de> for Signature where +Signature: for<'a> TryFrom<&'a[u8]>{ fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let signature_hex = array_bytes::hex2bytes(&String::deserialize(deserializer)?) .map_err(|e| de::Error::custom(format!("{:?}", e)))?; - Signature::try_from(signature_hex.as_ref()) - .map_err(|e| de::Error::custom(format!("{:?}", e))) + let sighex_ref = signature_hex.as_ref(); + Signature::try_from(sighex_ref) + .map_err(|e| de::Error::custom(format!("Error in converting deserialized data into signature"))) } } @@ -337,7 +354,7 @@ impl sp_std::fmt::Debug for Signature { +impl sp_std::fmt::Debug for Signature where [u8;LEFT_PLUS_RIGHT_LEN]: crate::hexdisplay::AsBytesRef{ #[cfg(feature = "std")] fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.inner)) @@ -351,8 +368,8 @@ impl UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]> for Signature where Signature: SignaturePair { fn unchecked_from(data: [u8; LEFT_PLUS_RIGHT_LEN]) -> Self { - let mut left : LeftSignature = data[0..Self::LEFT_SIGNATURE_LEN].try_into().unwrap(); - let mut right : RightSignature = data[Self::LEFT_SIGNATURE_LEN..LEFT_PLUS_RIGHT_LEN].try_into().unwrap(); + let Ok(mut left) = data[0..Self::LEFT_SIGNATURE_LEN].try_into() else { panic!("invalid signature") }; + let Ok(mut right) = data[Self::LEFT_SIGNATURE_LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { panic!("invalid signature") }; let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; Signature { left, right, inner } @@ -362,7 +379,8 @@ impl { +pub struct Pair +{ left: LeftPair, right: RightPair, @@ -383,64 +401,87 @@ trait HardJunctionId { } #[cfg(feature = "full_crypto")] -impl Pair { +impl Pair { } #[cfg(feature = "full_crypto")] -impl TraitPair for Pair where - Pair: DoublePair + CryptoType, +impl TraitPair for Pair where + Pair: DoublePair + CryptoType, LeftPair::Signature: SignatureBound, RightPair::Signature: SignatureBound, +Public: CryptoType, +Signature: SignaturePair, + LeftPair::Seed: SeedBound, + RightPair::Seed: SeedBound, +Seed: SeedBound, { - type Seed = (LeftPair::Seed, RightPair::Seed); - type Public = Public::PUBLIC_KEY_LEN}>; - type Signature = Signature; + type Seed = Seed; + type Public = Public; + type Signature = Signature; fn from_seed_slice(seed_slice: &[u8]) -> Result { if seed_slice.len() != Self::RIGHT_SEED_LEN + Self::LEFT_SEED_LEN { return Err(SecretStringError::InvalidSeedLength) } - let left = LeftPair::from_seed_slice(seed_slice[0..Self::LEFT_SEED_LEN])?; - let right = RightPair::from_seed_slice(seed_slice[Self::LEFT_SEED_LEN..Self::RIGHT_SEED_LEN + Self::LEFT_SEED_LEN])?; + let left = LeftPair::from_seed_slice(&seed_slice[0..Self::LEFT_SEED_LEN])?; + let right = RightPair::from_seed_slice(&seed_slice[Self::LEFT_SEED_LEN..Self::RIGHT_SEED_LEN + Self::LEFT_SEED_LEN])?; Ok(Pair { left, right }) } - // fn derive>( - // &self, - // path: Iter, - // _seed: Option, - // ) -> Result<(Self, Option), DeriveError> { - // let mut acc: [u8; SECRET_KEY_SERIALIZED_SIZE] = - // self.0.secret.to_bytes().try_into().expect( - // "Secret key serializer returns a vector of SECRET_KEY_SERIALIZED_SIZE size", - // ); - // for j in path { - // match j { - // DeriveJunction::Soft(_cc) => return Err(DeriveError::SoftKeyInPath), - // DeriveJunction::Hard(cc) => acc = derive_hard_junction::(&acc, &cc), - // } - // } - // Ok((Self::from_seed(&acc), Some(acc))) - // } - - // fn public(&self) -> Self::Public { - // let mut raw = [0u8; PUBLIC_KEY_SERIALIZED_SIZE]; - // let pk = DoublePublicKeyScheme::into_double_public_key(&self.0).to_bytes(); - // raw.copy_from_slice(pk.as_slice()); - // Self::Public::unchecked_from(raw) - // } + fn derive>( + &self, + path: Iter, + seed: Option, + ) -> Result<(Self, Option), DeriveError> { + + let seed_left_right = match seed { + Some(seed) => (Some(seed.left), Some(seed.right)), + //(LeftPair::from_seed_slice(&seed).ok().map(|p|p.to_raw_vec()), RightPair::from_seed_slice(&seed).ok().map(|p| p.to_raw_vec())), + None => (None, None), + }; + + let left_path: Vec<_> = path.map(|p|p.clone()).collect(); + let right_path = left_path.clone(); + let derived_left = self.left.derive(left_path.into_iter(), seed_left_right.0)?; + let derived_right = self.right.derive(right_path.into_iter(), seed_left_right.1)?; + + let optional_seed = match (derived_left.1, derived_right.1) { + (Some(seed_left), Some(seed_right)) => { + let mut inner = [0u8; DOUBLE_SEED_LEN]; + inner.copy_from_slice(seed_left.as_ref()); + inner[SECURE_SEED_LEN..].copy_from_slice(seed_right.as_ref()); + Some(Self::Seed{left: seed_left, right: seed_right, inner: inner})}, + _ => None, + + }; + // Some(seed) => (LeftPair::from_seed_slice(&seed).ok().map(|p|p.to_raw_vec()), RightPair::from_seed_slice(&seed).ok().map(|p| p.to_raw_vec())), + // None => (None, None), + // }; + + Ok((Self{left: derived_left.0, right: derived_right.0}, optional_seed)) + } + + fn public(&self) -> Self::Public { + let mut raw = [0u8; PUBLIC_KEY_LEN]; + let left_pub = self.left.public(); + let right_pub = self.right.public(); // let pk = DoublePublicKeyScheme::into_double_public_key(&self.0).to_bytes(); + raw.copy_from_slice(left_pub.as_ref()); + raw[LeftPair::Public::LEN..].copy_from_slice(right_pub.as_ref()); + Self::Public::unchecked_from(raw) + //Public{left: left_pub, right: right_pub, inner: raw} + } - // fn sign(&self, message: &[u8]) -> Self::Signature { - // let mut mutable_self = self.clone(); - // let r: [u8; SIGNATURE_SERIALIZED_SIZE] = + fn sign(&self, message: &[u8]) -> Self::Signature { + let mut mutable_self = self.clone(); + let r: [u8; SIGNATURE_LEN] = [0u8; SIGNATURE_LEN]; // DoublePublicKeyScheme::sign(&mut mutable_self.0, &Message::new(b"", message)) // .to_bytes() // .try_into() // .expect("Signature serializer returns vectors of SIGNATURE_SERIALIZED_SIZE size"); - // Self::Signature::unchecked_from(r) - // } + Self::Signature::unchecked_from(r) + } - // fn verify>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool { + fn verify>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool { // let pubkey_array: [u8; PUBLIC_KEY_SERIALIZED_SIZE] = // match <[u8; PUBLIC_KEY_SERIALIZED_SIZE]>::try_from(pubkey.as_ref()) { // Ok(pk) => pk, @@ -460,15 +501,12 @@ impl TraitPair for Pair return false, // }; - // sig.verify(&Message::new(b"", message.as_ref()), &public_key) - // } + // sig.verify(&Message::new(b"", message.as_ref()), &public_key) + return false; + } - // /// Get the seed for this key. - // fn to_raw_vec(&self) -> Vec { - // self.0 - // .secret - // .to_bytes() - // .try_into() - // .expect("Secret key serializer returns a vector of SECRET_KEY_SERIALIZED_SIZE size") - // } + /// Get the seed for this key. + fn to_raw_vec(&self) -> Vec { + [self.left.to_raw_vec(), self.left.to_raw_vec()].concat() + } } From 8f42ffeafed792ac5be7e7128b517b9e177f59af Mon Sep 17 00:00:00 2001 From: Skalman Date: Tue, 5 Sep 2023 16:58:31 -0400 Subject: [PATCH 09/13] implement sgin and verify for --- primitives/core/src/paired_crypto.rs | 36 +++++++--------------------- 1 file changed, 9 insertions(+), 27 deletions(-) diff --git a/primitives/core/src/paired_crypto.rs b/primitives/core/src/paired_crypto.rs index b76a7b42c0ff0..6f9abbc18c394 100644 --- a/primitives/core/src/paired_crypto.rs +++ b/primitives/core/src/paired_crypto.rs @@ -473,36 +473,17 @@ Seed: SeedBound, fn sign(&self, message: &[u8]) -> Self::Signature { let mut mutable_self = self.clone(); - let r: [u8; SIGNATURE_LEN] = [0u8; SIGNATURE_LEN]; - // DoublePublicKeyScheme::sign(&mut mutable_self.0, &Message::new(b"", message)) - // .to_bytes() - // .try_into() - // .expect("Signature serializer returns vectors of SIGNATURE_SERIALIZED_SIZE size"); + let mut r: [u8; SIGNATURE_LEN] = [0u8; SIGNATURE_LEN]; + r.copy_from_slice(self.left.sign(message).as_ref()); + r[Self::LEFT_SIGNATURE_LEN..].copy_from_slice(self.right.sign(message).as_ref()); Self::Signature::unchecked_from(r) } - fn verify>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool { - // let pubkey_array: [u8; PUBLIC_KEY_SERIALIZED_SIZE] = - // match <[u8; PUBLIC_KEY_SERIALIZED_SIZE]>::try_from(pubkey.as_ref()) { - // Ok(pk) => pk, - // Err(_) => return false, - // }; - // let public_key = match w3f_bls::double::DoublePublicKey::::from_bytes(&pubkey_array) { - // Ok(pk) => pk, - // Err(_) => return false, - // }; - - // let sig_array = match sig.inner[..].try_into() { - // Ok(s) => s, - // Err(_) => return false, - // }; - // let sig = match w3f_bls::double::DoubleSignature::from_bytes(sig_array) { - // Ok(s) => s, - // Err(_) => return false, - // }; - - // sig.verify(&Message::new(b"", message.as_ref()), &public_key) - return false; + fn verify>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool { + let mut vec_message = vec![0u8; message.as_ref().len()]; + vec_message.clone_from_slice(message.as_ref()); + + LeftPair::verify(&sig.left, message, &pubkey.left) && RightPair::verify(&sig.right, vec_message, &pubkey.right) } /// Get the seed for this key. @@ -510,3 +491,4 @@ Seed: SeedBound, [self.left.to_raw_vec(), self.left.to_raw_vec()].concat() } } + From 5b96d95361a6d6f8c36e72f63403221465782be1 Mon Sep 17 00:00:00 2001 From: Skalman Date: Sun, 10 Sep 2023 14:02:12 -0400 Subject: [PATCH 10/13] Actually implementing `paired_crypto::{Pair, Public, Signatrue}` for paired (ECDSA, BLS377) crypto --- primitives/core/src/bls.rs | 4 +- primitives/core/src/paired_crypto.rs | 104 +++++++++++++++++++++------ 2 files changed, 83 insertions(+), 25 deletions(-) diff --git a/primitives/core/src/bls.rs b/primitives/core/src/bls.rs index 770f7d65cea05..abc87709f1634 100644 --- a/primitives/core/src/bls.rs +++ b/primitives/core/src/bls.rs @@ -89,11 +89,11 @@ const SECRET_KEY_SERIALIZED_SIZE: usize = as SerializableToBytes>::SERIALIZED_BYTES_SIZE; // Public key serialized size -const PUBLIC_KEY_SERIALIZED_SIZE: usize = +pub const PUBLIC_KEY_SERIALIZED_SIZE: usize = as SerializableToBytes>::SERIALIZED_BYTES_SIZE; // Signature serialized size -const SIGNATURE_SERIALIZED_SIZE: usize = +pub const SIGNATURE_SERIALIZED_SIZE: usize = as SerializableToBytes>::SERIALIZED_BYTES_SIZE; /// A secret seed. diff --git a/primitives/core/src/paired_crypto.rs b/primitives/core/src/paired_crypto.rs index 6f9abbc18c394..a43f030fdc0f0 100644 --- a/primitives/core/src/paired_crypto.rs +++ b/primitives/core/src/paired_crypto.rs @@ -35,34 +35,61 @@ use sp_runtime_interface::pass_by::PassByInner; use sp_std::{convert::TryFrom, marker::PhantomData, ops::Deref}; /// ECDSA and BLS-377 specialized types +#[cfg(feature = "bls-experimental")] pub mod ecdsa_n_bls377 { use crate::crypto::{CryptoTypeId}; - use crate::{ecdsa, ed25519}; + use crate::{ecdsa, ed25519, bls377}; - /// An identifier used to match public keys against BLS12-377 keys - pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecb7"); - - /// BLS12-377 key pair. - #[cfg(feature = "full_crypto")] - pub type Pair = super::Pair; + /// An identifier used to match public keys against BLS12-377 keys + pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecb7"); + + const PUBLIC_KEY_LEN :usize = 33 + crate::bls::PUBLIC_KEY_SERIALIZED_SIZE; + const LEFT_SIGNATURE_LEN :usize = 64; + const RIGHT_SIGNATURE_LEN :usize = crate::bls::SIGNATURE_SERIALIZED_SIZE; + const SIGNATURE_LEN: usize = LEFT_SIGNATURE_LEN + RIGHT_SIGNATURE_LEN; + const LEFT_SEED_LEN: usize = 32; + const RIGHT_SEED_LEN: usize = 32; + + /// BLS12-377 key pair. + #[cfg(feature = "full_crypto")] + pub type Pair = super::Pair; /// BLS12-377 public key. - pub type Public = super::Public; + pub type Public = super::Public; // /// BLS12-377 signature. - //pub type Signature = super::Signature; - - // impl super::CryptoType for Public - // { - // #[cfg(feature = "full_crypto")] - // type Pair = Pair; - // } - // impl super::HardJunctionId for TinyBLS377 { - // const ID: &'static str = "BLS12377HDKD"; - // } - -// impl CryptoType for Signature { -// #[cfg(feature = "full_crypto")] -// type Pair = Pair; -// } + pub type Signature = super::Signature; + + impl super::SignaturePair for Signature { + const LEFT_SIGNATURE_LEN: usize = LEFT_SIGNATURE_LEN; + const RIGHT_SIGNATURE_LEN: usize = RIGHT_SIGNATURE_LEN; + const LEFT_PLUS_RIGHT_LEN: usize = SIGNATURE_LEN; + } + + #[cfg(feature = "full_crypto")] + impl super::DoublePair for Pair{ + const PUBLIC_KEY_LEN: usize = PUBLIC_KEY_LEN; + const LEFT_SIGNATURE_LEN: usize = LEFT_SIGNATURE_LEN; + const RIGHT_SIGNATURE_LEN:usize = RIGHT_SIGNATURE_LEN; + const SIGNATURE_LEN: usize = SIGNATURE_LEN; + const LEFT_SEED_LEN: usize = LEFT_SEED_LEN; + const RIGHT_SEED_LEN: usize = RIGHT_SEED_LEN; + } + + impl super::CryptoType for Public + { + #[cfg(feature = "full_crypto")] + type Pair = Pair; + } + + impl super::CryptoType for Signature { + #[cfg(feature = "full_crypto")] + type Pair = Pair; + } + + #[cfg(feature = "full_crypto")] + impl super::CryptoType for Pair{ + type Pair = Pair; + } + } @@ -80,12 +107,40 @@ const DOUBLE_SEED_LEN: usize = SECURE_SEED_LEN * 2; #[cfg(feature = "full_crypto")] pub trait SeedBound: Default + AsRef<[u8]> + AsMut<[u8]> + Clone {} +impl + AsMut<[u8]> + Clone> SeedBound for SeedTrait {} + #[cfg(feature = "full_crypto")] +#[derive(Clone)] pub struct Seed { left: LeftSeed, right: RightSeed, inner: [u8; LEFT_PLUS_RIGHT_LEN], } + +#[cfg(feature = "full_crypto")] +impl Default for Seed { + fn default() -> Self{ + Self { + left: LeftSeed::default(), right: RightSeed::default(), inner: [LeftSeed::default().as_ref(), RightSeed::default().as_ref()].concat().try_into().unwrap() + } + } +} + +#[cfg(feature = "full_crypto")] +impl AsRef<[u8]> for Seed { + fn as_ref(&self) -> &[u8] { + &self.inner[..] + } +} + +#[cfg(feature = "full_crypto")] +impl AsMut<[u8]> for Seed { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.inner[..] + } +} + + //pub trait Public: ByteArray + Derive + CryptoType + PartialEq + Eq + Clone + Send + Sync {} pub trait PublicKeyBound: TraitPublic + Sized + Derive + sp_std::hash::Hash + ByteArray + for<'a> TryFrom<&'a[u8]> + AsMut<[u8]> + CryptoType {} @@ -263,6 +318,8 @@ impl TryFrom<&'a[u8]> + AsRef<[u8]> {} +impl TryFrom<&'a[u8]> + AsRef<[u8]>> SignatureBound for SignatureTrait {} + /// A pair of signatures of different types #[derive(Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq)] #[scale_info(skip_type_params(T))] @@ -492,3 +549,4 @@ Seed: SeedBound, } } + From 3208ad0318bf59724c0bdf21163f30ce14a7ba18 Mon Sep 17 00:00:00 2001 From: Skalman Date: Mon, 11 Sep 2023 05:58:28 -0400 Subject: [PATCH 11/13] Implement and pass all test for `paired_crypto` --- primitives/core/src/crypto.rs | 2 +- primitives/core/src/hexdisplay.rs | 2 +- primitives/core/src/paired_crypto.rs | 242 +++++++++++++++++++++++---- 3 files changed, 216 insertions(+), 30 deletions(-) diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index 72f996b336832..74a0a71381ae0 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -1195,7 +1195,7 @@ macro_rules! impl_from_entropy_base { [$type; 17], [$type; 18], [$type; 19], [$type; 20], [$type; 21], [$type; 22], [$type; 23], [$type; 24], [$type; 25], [$type; 26], [$type; 27], [$type; 28], [$type; 29], [$type; 30], [$type; 31], [$type; 32], [$type; 36], [$type; 40], [$type; 44], [$type; 48], [$type; 56], [$type; 64], [$type; 72], [$type; 80], - [$type; 96], [$type; 112], [$type; 128], [$type; 160], [$type; 192], [$type; 224], [$type; 256] + [$type; 96], [$type; 112], [$type; 128], [$type; 160], [$type; 177], [$type; 192], [$type; 224], [$type; 256] ); } } diff --git a/primitives/core/src/hexdisplay.rs b/primitives/core/src/hexdisplay.rs index 30e045dfc52ac..72bb24a186e54 100644 --- a/primitives/core/src/hexdisplay.rs +++ b/primitives/core/src/hexdisplay.rs @@ -96,7 +96,7 @@ macro_rules! impl_non_endians { impl_non_endians!( [u8; 1], [u8; 2], [u8; 3], [u8; 4], [u8; 5], [u8; 6], [u8; 7], [u8; 8], [u8; 10], [u8; 12], [u8; 14], [u8; 16], [u8; 20], [u8; 24], [u8; 28], [u8; 32], [u8; 40], [u8; 48], [u8; 56], - [u8; 64], [u8; 65], [u8; 80], [u8; 96], [u8; 112], [u8; 128], [u8; 144] + [u8; 64], [u8; 65], [u8; 80], [u8; 96], [u8; 112], [u8; 128], [u8; 144], [u8; 177] ); /// Format into ASCII + # + hex, suitable for storage key preimages. diff --git a/primitives/core/src/paired_crypto.rs b/primitives/core/src/paired_crypto.rs index a43f030fdc0f0..81d41a52394c4 100644 --- a/primitives/core/src/paired_crypto.rs +++ b/primitives/core/src/paired_crypto.rs @@ -39,16 +39,17 @@ use sp_std::{convert::TryFrom, marker::PhantomData, ops::Deref}; pub mod ecdsa_n_bls377 { use crate::crypto::{CryptoTypeId}; use crate::{ecdsa, ed25519, bls377}; + use super::{SECURE_SEED_LEN, DOUBLE_SEED_LEN}; /// An identifier used to match public keys against BLS12-377 keys pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecb7"); const PUBLIC_KEY_LEN :usize = 33 + crate::bls::PUBLIC_KEY_SERIALIZED_SIZE; - const LEFT_SIGNATURE_LEN :usize = 64; + const LEFT_SIGNATURE_LEN :usize = 65; const RIGHT_SIGNATURE_LEN :usize = crate::bls::SIGNATURE_SERIALIZED_SIZE; const SIGNATURE_LEN: usize = LEFT_SIGNATURE_LEN + RIGHT_SIGNATURE_LEN; - const LEFT_SEED_LEN: usize = 32; - const RIGHT_SEED_LEN: usize = 32; + const LEFT_SEED_LEN: usize = SECURE_SEED_LEN; + const RIGHT_SEED_LEN: usize = SECURE_SEED_LEN; /// BLS12-377 key pair. #[cfg(feature = "full_crypto")] @@ -58,6 +59,8 @@ pub mod ecdsa_n_bls377 { // /// BLS12-377 signature. pub type Signature = super::Signature; + pub type Seed = super::Seed<[u8; SECURE_SEED_LEN], [u8; SECURE_SEED_LEN], DOUBLE_SEED_LEN,>; + impl super::SignaturePair for Signature { const LEFT_SIGNATURE_LEN: usize = LEFT_SIGNATURE_LEN; const RIGHT_SIGNATURE_LEN: usize = RIGHT_SIGNATURE_LEN; @@ -90,6 +93,22 @@ pub mod ecdsa_n_bls377 { type Pair = Pair; } + impl<'a> TryFrom<&'a[u8]> for Seed { + type Error = (); + + fn try_from(data: &[u8]) -> Result { + if data.len() != DOUBLE_SEED_LEN { + return Err(()) + } + let mut left : [u8; 32] = data[0..SECURE_SEED_LEN].try_into().unwrap(); + let mut right : [u8; 32] = data[SECURE_SEED_LEN..DOUBLE_SEED_LEN].try_into().unwrap(); + + let mut inner = [0u8; DOUBLE_SEED_LEN]; + inner.copy_from_slice(data); + Ok(Seed { left, right, inner }) + + } + } } @@ -141,6 +160,8 @@ impl TryFrom<&'a[u8]> + AsMut<[u8]> + CryptoType {} @@ -184,13 +205,14 @@ impl<'a,LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS type Error = (); fn try_from(data: &[u8]) -> Result { - if data.len() != LEFT_PLUS_RIGHT_LEN { - return Err(()) - } - let mut left : LeftPublic = data[0..LeftPublic::LEN].try_into()?; + if data.len() != LEFT_PLUS_RIGHT_LEN { + return Err(()) + } + let mut left : LeftPublic = data[0..LeftPublic::LEN].try_into()?; let mut right : RightPublic = data[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into()?; let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; + inner.copy_from_slice(data); Ok(Public { left, right, inner }) } @@ -226,7 +248,7 @@ impl Self { - let mut left : LeftPublic = inner[0..LeftPublic::LEN].try_into().unwrap(); + let mut left : LeftPublic = inner[0..LeftPublic::LEN].try_into().unwrap(); let mut right : RightPublic = inner[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into().unwrap(); Self { left, right, inner } @@ -354,7 +376,7 @@ impl<'a,LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEF let Ok(mut right) : Result= data[Self::LEFT_SIGNATURE_LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { panic!("invalid signature") }; let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; - inner.copy_from_slice(left.as_ref()); + inner[..Self::LEFT_SIGNATURE_LEN].copy_from_slice(left.as_ref()); inner[Self::LEFT_SIGNATURE_LEN..].copy_from_slice(right.as_ref()); Ok(Signature { left, right, inner }) @@ -428,8 +450,7 @@ impl: SeedBound, type Signature = Signature; fn from_seed_slice(seed_slice: &[u8]) -> Result { - if seed_slice.len() != Self::RIGHT_SEED_LEN + Self::LEFT_SEED_LEN { - return Err(SecretStringError::InvalidSeedLength) - } - let left = LeftPair::from_seed_slice(&seed_slice[0..Self::LEFT_SEED_LEN])?; - let right = RightPair::from_seed_slice(&seed_slice[Self::LEFT_SEED_LEN..Self::RIGHT_SEED_LEN + Self::LEFT_SEED_LEN])?; - Ok(Pair { left, right }) + if seed_slice.len() != Self::RIGHT_SEED_LEN + Self::LEFT_SEED_LEN { + return Err(SecretStringError::InvalidSeedLength) + } + let left = LeftPair::from_seed_slice(&seed_slice[0..Self::LEFT_SEED_LEN])?; + let right = RightPair::from_seed_slice(&seed_slice[Self::LEFT_SEED_LEN..Self::RIGHT_SEED_LEN + Self::LEFT_SEED_LEN])?; + Ok(Pair { left, right }) } fn derive>( @@ -493,20 +514,19 @@ Seed: SeedBound, let seed_left_right = match seed { Some(seed) => (Some(seed.left), Some(seed.right)), - //(LeftPair::from_seed_slice(&seed).ok().map(|p|p.to_raw_vec()), RightPair::from_seed_slice(&seed).ok().map(|p| p.to_raw_vec())), - None => (None, None), + None => (None, None), }; let left_path: Vec<_> = path.map(|p|p.clone()).collect(); let right_path = left_path.clone(); - let derived_left = self.left.derive(left_path.into_iter(), seed_left_right.0)?; + let derived_left = self.left.derive(left_path.into_iter(), seed_left_right.0)?; let derived_right = self.right.derive(right_path.into_iter(), seed_left_right.1)?; let optional_seed = match (derived_left.1, derived_right.1) { (Some(seed_left), Some(seed_right)) => { let mut inner = [0u8; DOUBLE_SEED_LEN]; - inner.copy_from_slice(seed_left.as_ref()); - inner[SECURE_SEED_LEN..].copy_from_slice(seed_right.as_ref()); + inner[..Self::LEFT_SEED_LEN].copy_from_slice(seed_left.as_ref()); + inner[Self::LEFT_SEED_LEN..Self::LEFT_SEED_LEN + Self::RIGHT_SEED_LEN].copy_from_slice(seed_right.as_ref()); Some(Self::Seed{left: seed_left, right: seed_right, inner: inner})}, _ => None, @@ -520,9 +540,9 @@ Seed: SeedBound, fn public(&self) -> Self::Public { let mut raw = [0u8; PUBLIC_KEY_LEN]; - let left_pub = self.left.public(); - let right_pub = self.right.public(); // let pk = DoublePublicKeyScheme::into_double_public_key(&self.0).to_bytes(); - raw.copy_from_slice(left_pub.as_ref()); + let left_pub = self.left.public(); + let right_pub = self.right.public(); // let pk = DoublePublicKeyScheme::into_double_public_key(&self.0).to_bytes(); + raw[..LeftPair::Public::LEN].copy_from_slice(left_pub.as_ref()); raw[LeftPair::Public::LEN..].copy_from_slice(right_pub.as_ref()); Self::Public::unchecked_from(raw) //Public{left: left_pub, right: right_pub, inner: raw} @@ -531,8 +551,8 @@ Seed: SeedBound, fn sign(&self, message: &[u8]) -> Self::Signature { let mut mutable_self = self.clone(); let mut r: [u8; SIGNATURE_LEN] = [0u8; SIGNATURE_LEN]; - r.copy_from_slice(self.left.sign(message).as_ref()); - r[Self::LEFT_SIGNATURE_LEN..].copy_from_slice(self.right.sign(message).as_ref()); + r[..Self::LEFT_SIGNATURE_LEN].copy_from_slice(self.left.sign(message).as_ref()); + r[Self::LEFT_SIGNATURE_LEN..].copy_from_slice(self.right.sign(message).as_ref()); Self::Signature::unchecked_from(r) } @@ -545,8 +565,174 @@ Seed: SeedBound, /// Get the seed for this key. fn to_raw_vec(&self) -> Vec { - [self.left.to_raw_vec(), self.left.to_raw_vec()].concat() + [self.left.to_raw_vec(), self.right.to_raw_vec()].concat() } } + +// Test set exercising the BLS12-377 implementation +#[cfg(test)] +mod test { + use super::*; + use crate::crypto::DEV_PHRASE; + use ecdsa_n_bls377::{Pair, Signature, Seed}; + use hex_literal::hex; + + + #[test] + fn default_phrase_should_be_used() { + assert_eq!( + Pair::from_string("//Alice///password", None).unwrap().public(), + Pair::from_string(&format!("{}//Alice", DEV_PHRASE), Some("password")) + .unwrap() + .public(), + ); + } + + #[test] + fn seed_and_derive_should_work() { + let seed_left = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); + let seed_right = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f00"); + let pair = Pair::from_seed(&([seed_left,seed_right].concat()[..].try_into().unwrap())); + // we are using hash to field so this is not going to work + // assert_eq!(pair.seed(), seed); + let path = vec![DeriveJunction::Hard([0u8; 32])]; + let derived = pair.derive(path.into_iter(), None).ok().unwrap().0; + assert_eq!( + derived.to_raw_vec(), + [hex!("b8eefc4937200a8382d00050e050ced2d4ab72cc2ef1b061477afb51564fdd61"), hex!("a4f2269333b3e87c577aa00c4a2cd650b3b30b2e8c286a47c251279ff3a26e0d")].concat() + ); + } + + + #[test] + fn test_vector_should_work() { + let seed_left = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); + let seed_right = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); + let pair = Pair::from_seed(&([seed_left,seed_right].concat()[..].try_into().unwrap())); + let public = pair.public(); + assert_eq!( + public, + Public::unchecked_from( + hex!("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd917a84ca8ce4c37c93c95ecee6a3c0c9a7b9c225093cf2f12dc4f69cbfb847ef9424a18f5755d5a742247d386ff2aabb806bcf160eff31293ea9616976628f77266c8a8cc1d8753be04197bd6cdd8c5c87a148f782c4c1568d599b48833fd539001e580cff64bbc71850605433fcd051f3afc3b74819786f815ffb5272030a8d03e5df61e6183f8fd8ea85f26defa83400" + ), + ), + ); + let message = b""; + let signature = hex!("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00d1e3013161991e142d8751017d4996209c2ff8a9ee160f373733eda3b4b785ba6edce9f45f87104bbe07aa6aa6eb2780aa705efb2c13d3b317d6409d159d23bdc7cdd5c2a832d1551cf49d811d49c901495e527dbd532e3a462335ce2686009104aba7bc11c5b22be78f3198d2727a0b"); + let signature = Signature::unchecked_from(signature); + assert!(pair.sign(&message[..]) == signature); + assert!(Pair::verify(&signature, &message[..], &public)); + } + + #[test] + fn test_vector_by_string_should_work() { + let pair = Pair::from_string("0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f609d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", + None, + ) + .unwrap(); + let public = pair.public(); + assert_eq!( + public, + Public::unchecked_from( + hex!("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd916dc6be608fab3c6bd894a606be86db346cc170db85c733853a371f3db54ae1b12052c0888d472760c81b537572a26f00db865e5963aef8634f9917571c51b538b564b2a9ceda938c8b930969ee3b832448e08e33a79e9ddd28af419a3ce45300f5dbc768b067781f44f3fe05a19e6b07b1c4196151ec3f8ea37e4f89a8963030d2101e931276bb9ebe1f20102239d780" + ), + ), + ); + let message = b""; + let signature = hex!("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00bbb395bbdee1a35930912034f5fde3b36df2835a0536c865501b0675776a1d5931a3bea2e66eff73b2546c6af2061a8019223e4ebbbed661b2538e0f5823f2c708eb89c406beca8fcb53a5c13dbc7c0c42e4cf2be2942bba96ea29297915a06bd2b1b979c0e2ac8fd4ec684a6b5d110c"); + let signature = Signature::unchecked_from(signature); + assert!(pair.sign(&message[..]) == signature); + assert!(Pair::verify(&signature, &message[..], &public)); + } + + #[test] + fn generated_pair_should_work() { + let (pair, _) = Pair::generate(); + let public = pair.public(); + let message = b"Something important"; + let signature = pair.sign(&message[..]); + assert!(Pair::verify(&signature, &message[..], &public)); + assert!(!Pair::verify(&signature, b"Something else", &public)); + } + + + #[test] + fn seeded_pair_should_work() { + let pair = Pair::from_seed(&(b"1234567890123456789012345678901212345678901234567890123456789012".as_slice().try_into().unwrap())); + let public = pair.public(); + assert_eq!( + public, + Public::unchecked_from( + hex!("035676109c54b9a16d271abeb4954316a40a32bcce023ac14c8e26e958aa68fba9754d2f2bbfa67df54d7e0e951979a18a1e0f45948857752cc2bac6bbb0b1d05e8e48bcc453920bf0c4bbd5993212480112a1fb433f04d74af0a8b700d93dc957ab3207f8d071e948f5aca1a7632c00bdf6d06be05b43e2e6216dccc8a5d55a0071cb2313cfd60b7e9114619cd17c06843b352f0b607a99122f6651df8f02e1ad3697bd208e62af047ddd7b942ba80080") + ), + ); + let message = + hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000" + ); + let signature = pair.sign(&message[..]); + println!("Correct signature: {:?}", signature); + assert!(Pair::verify(&signature, &message[..], &public)); + assert!(!Pair::verify(&signature, "Other message", &public)); + } + + #[test] + fn generate_with_phrase_recovery_possible() { + let (pair1, phrase, _) = Pair::generate_with_phrase(None); + let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap(); + + assert_eq!(pair1.public(), pair2.public()); + } + + #[test] + fn generate_with_password_phrase_recovery_possible() { + let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password")); + let (pair2, _) = Pair::from_phrase(&phrase, Some("password")).unwrap(); + + assert_eq!(pair1.public(), pair2.public()); + } + + #[test] + fn password_does_something() { + let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password")); + let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap(); + + assert_ne!(pair1.public(), pair2.public()); + } + + #[test] + fn ss58check_roundtrip_works() { + let pair = Pair::from_seed(&(b"1234567890123456789012345678901212345678901234567890123456789012".as_slice().try_into().unwrap())); + let public = pair.public(); + let s = public.to_ss58check(); + println!("Correct: {}", s); + let cmp = Public::from_ss58check(&s).unwrap(); + assert_eq!(cmp, public); + } + + #[test] + fn signature_serialization_works() { + let pair = Pair::from_seed(&(b"1234567890123456789012345678901212345678901234567890123456789012".as_slice().try_into().unwrap())); + let message = b"Something important"; + let signature = pair.sign(&message[..]); + + let serialized_signature = serde_json::to_string(&signature).unwrap(); + println!("{:?} -- {:}", signature.inner, serialized_signature); + // Signature is 177 bytes, hexify * 2, so 354 chars + 2 quote charsy + assert_eq!(serialized_signature.len(), 356); + let signature = serde_json::from_str(&serialized_signature).unwrap(); + assert!(Pair::verify(&signature, &message[..], &pair.public())); + } + + #[test] + fn signature_serialization_doesnt_panic() { + fn deserialize_signature(text: &str) -> Result { + serde_json::from_str(text) + } + assert!(deserialize_signature("Not valid json.").is_err()); + assert!(deserialize_signature("\"Not an actual signature.\"").is_err()); + // Poorly-sized + assert!(deserialize_signature("\"abc123\"").is_err()); + } +} From 854c32d2107c73070ae6dc2d41b9ab689bce69c9 Mon Sep 17 00:00:00 2001 From: Skalman Date: Mon, 25 Sep 2023 12:00:46 -0400 Subject: [PATCH 12/13] - move to signle seed for both schemes in `primitives/core/src/paired_crypto.rs` - put serialize and descerialze under `serde` feature instead of std in `primitives/core/src/bls.rs` - fix documentation in `primitives/core/src/bls.rs` --- primitives/core/src/bls.rs | 19 +- primitives/core/src/paired_crypto.rs | 474 +++++++++++---------------- 2 files changed, 208 insertions(+), 285 deletions(-) diff --git a/primitives/core/src/bls.rs b/primitives/core/src/bls.rs index abc87709f1634..781280cc1f1cf 100644 --- a/primitives/core/src/bls.rs +++ b/primitives/core/src/bls.rs @@ -83,16 +83,16 @@ trait BlsBound: EngineBLS + HardJunctionId + Send + Sync + 'static {} impl BlsBound for T {} -// Secret key serialized size +/// Secret key serialized size #[cfg(feature = "full_crypto")] const SECRET_KEY_SERIALIZED_SIZE: usize = as SerializableToBytes>::SERIALIZED_BYTES_SIZE; -// Public key serialized size +/// Public key serialized size pub const PUBLIC_KEY_SERIALIZED_SIZE: usize = as SerializableToBytes>::SERIALIZED_BYTES_SIZE; -// Signature serialized size +/// Signature serialized size pub const SIGNATURE_SERIALIZED_SIZE: usize = as SerializableToBytes>::SERIALIZED_BYTES_SIZE; @@ -254,7 +254,7 @@ impl sp_std::fmt::Debug for Public { } } -#[cfg(feature = "std")] +#[cfg(feature = "serde")] impl Serialize for Public { fn serialize(&self, serializer: S) -> Result where @@ -264,7 +264,7 @@ impl Serialize for Public { } } -#[cfg(feature = "std")] +#[cfg(feature = "serde")] impl<'de, T: BlsBound> Deserialize<'de> for Public { fn deserialize(deserializer: D) -> Result where @@ -326,7 +326,7 @@ impl TryFrom<&[u8]> for Signature { } } -#[cfg(feature = "std")] +#[cfg(feature = "serde")] impl Serialize for Signature { fn serialize(&self, serializer: S) -> Result where @@ -336,7 +336,7 @@ impl Serialize for Signature { } } -#[cfg(feature = "std")] +#[cfg(feature = "serde")] impl<'de, T> Deserialize<'de> for Signature { fn deserialize(deserializer: D) -> Result where @@ -526,10 +526,9 @@ mod test { ); } - // Only passes if the seed = (seed mod ScalarField) #[test] fn seed_and_derive_should_work() { - let seed = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f00"); + let seed = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); let pair = Pair::from_seed(&seed); // we are using hash to field so this is not going to work // assert_eq!(pair.seed(), seed); @@ -537,7 +536,7 @@ mod test { let derived = pair.derive(path.into_iter(), None).ok().unwrap().0; assert_eq!( derived.to_raw_vec(), - hex!("a4f2269333b3e87c577aa00c4a2cd650b3b30b2e8c286a47c251279ff3a26e0d") + hex!("3a0626d095148813cd1642d38254f1cfff7eb8cc1a2fc83b2a135377c3554c12") ); } diff --git a/primitives/core/src/paired_crypto.rs b/primitives/core/src/paired_crypto.rs index 81d41a52394c4..872dd64d9381b 100644 --- a/primitives/core/src/paired_crypto.rs +++ b/primitives/core/src/paired_crypto.rs @@ -10,7 +10,7 @@ // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software -// distributed under the Licenseff is distributed on an "AS IS" BASIS, +// distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. @@ -32,14 +32,13 @@ use scale_info::TypeInfo; use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use sp_runtime_interface::pass_by::PassByInner; -use sp_std::{convert::TryFrom, marker::PhantomData, ops::Deref}; +use sp_std::convert::TryFrom; -/// ECDSA and BLS-377 specialized types +/// ECDSA and BLS-377 paired crypto scheme #[cfg(feature = "bls-experimental")] pub mod ecdsa_n_bls377 { use crate::crypto::{CryptoTypeId}; - use crate::{ecdsa, ed25519, bls377}; - use super::{SECURE_SEED_LEN, DOUBLE_SEED_LEN}; + use crate::{ecdsa, bls377}; /// An identifier used to match public keys against BLS12-377 keys pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecb7"); @@ -48,33 +47,25 @@ pub mod ecdsa_n_bls377 { const LEFT_SIGNATURE_LEN :usize = 65; const RIGHT_SIGNATURE_LEN :usize = crate::bls::SIGNATURE_SERIALIZED_SIZE; const SIGNATURE_LEN: usize = LEFT_SIGNATURE_LEN + RIGHT_SIGNATURE_LEN; - const LEFT_SEED_LEN: usize = SECURE_SEED_LEN; - const RIGHT_SEED_LEN: usize = SECURE_SEED_LEN; - /// BLS12-377 key pair. + /// (ECDSA, BLS12-377) key-pair pair. #[cfg(feature = "full_crypto")] pub type Pair = super::Pair; - /// BLS12-377 public key. + /// (ECDSA, BLS12-377) public key pair. pub type Public = super::Public; - // /// BLS12-377 signature. + /// (ECDSA, BLS12-377) signature pair. pub type Signature = super::Signature; - - pub type Seed = super::Seed<[u8; SECURE_SEED_LEN], [u8; SECURE_SEED_LEN], DOUBLE_SEED_LEN,>; impl super::SignaturePair for Signature { - const LEFT_SIGNATURE_LEN: usize = LEFT_SIGNATURE_LEN; - const RIGHT_SIGNATURE_LEN: usize = RIGHT_SIGNATURE_LEN; - const LEFT_PLUS_RIGHT_LEN: usize = SIGNATURE_LEN; + const LEFT_SIGNATURE_LEN: usize = LEFT_SIGNATURE_LEN; + const RIGHT_SIGNATURE_LEN: usize = RIGHT_SIGNATURE_LEN; + const LEFT_PLUS_RIGHT_LEN: usize = SIGNATURE_LEN; } #[cfg(feature = "full_crypto")] impl super::DoublePair for Pair{ - const PUBLIC_KEY_LEN: usize = PUBLIC_KEY_LEN; - const LEFT_SIGNATURE_LEN: usize = LEFT_SIGNATURE_LEN; - const RIGHT_SIGNATURE_LEN:usize = RIGHT_SIGNATURE_LEN; - const SIGNATURE_LEN: usize = SIGNATURE_LEN; - const LEFT_SEED_LEN: usize = LEFT_SEED_LEN; - const RIGHT_SEED_LEN: usize = RIGHT_SEED_LEN; + const PUBLIC_KEY_LEN: usize = PUBLIC_KEY_LEN; + const SIGNATURE_LEN: usize = SIGNATURE_LEN; } impl super::CryptoType for Public @@ -84,85 +75,31 @@ pub mod ecdsa_n_bls377 { } impl super::CryptoType for Signature { - #[cfg(feature = "full_crypto")] - type Pair = Pair; + #[cfg(feature = "full_crypto")] + type Pair = Pair; } #[cfg(feature = "full_crypto")] impl super::CryptoType for Pair{ - type Pair = Pair; - } - - impl<'a> TryFrom<&'a[u8]> for Seed { - type Error = (); - - fn try_from(data: &[u8]) -> Result { - if data.len() != DOUBLE_SEED_LEN { - return Err(()) - } - let mut left : [u8; 32] = data[0..SECURE_SEED_LEN].try_into().unwrap(); - let mut right : [u8; 32] = data[SECURE_SEED_LEN..DOUBLE_SEED_LEN].try_into().unwrap(); - - let mut inner = [0u8; DOUBLE_SEED_LEN]; - inner.copy_from_slice(data); - Ok(Seed { left, right, inner }) - - } + type Pair = Pair; } } +/// currently only supporting sub-schemes whose seed is a 32-bytes array. #[cfg(feature = "full_crypto")] const SECURE_SEED_LEN: usize = 32; -#[cfg(feature = "full_crypto")] -const DOUBLE_SEED_LEN: usize = SECURE_SEED_LEN * 2; - /// A secret seed. /// /// It's not called a "secret key" because ring doesn't expose the secret keys /// of the key pair (yeah, dumb); as such we're forced to remember the seed manually if we /// will need it later (such as for HDKD). #[cfg(feature = "full_crypto")] -pub trait SeedBound: Default + AsRef<[u8]> + AsMut<[u8]> + Clone {} - -impl + AsMut<[u8]> + Clone> SeedBound for SeedTrait {} - -#[cfg(feature = "full_crypto")] -#[derive(Clone)] -pub struct Seed { - left: LeftSeed, - right: RightSeed, - inner: [u8; LEFT_PLUS_RIGHT_LEN], -} - -#[cfg(feature = "full_crypto")] -impl Default for Seed { - fn default() -> Self{ - Self { - left: LeftSeed::default(), right: RightSeed::default(), inner: [LeftSeed::default().as_ref(), RightSeed::default().as_ref()].concat().try_into().unwrap() - } - } -} - -#[cfg(feature = "full_crypto")] -impl AsRef<[u8]> for Seed { - fn as_ref(&self) -> &[u8] { - &self.inner[..] - } -} - -#[cfg(feature = "full_crypto")] -impl AsMut<[u8]> for Seed { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.inner[..] - } -} - - +type Seed = [u8; SECURE_SEED_LEN]; -//pub trait Public: ByteArray + Derive + CryptoType + PartialEq + Eq + Clone + Send + Sync {} +/// trait characterizing Public key which could be used as individual component of an `paired_crypto:Public` pair. pub trait PublicKeyBound: TraitPublic + Sized + Derive + sp_std::hash::Hash + ByteArray + for<'a> TryFrom<&'a[u8]> + AsMut<[u8]> + CryptoType {} impl TryFrom<&'a[u8]> + AsMut<[u8]> + CryptoType> PublicKeyBound for PublicKeyTrait {} @@ -176,7 +113,7 @@ pub struct Public Public { // inline fn left<'a>(&self)-> &'a LeftPublic { // &LeftPublic::try_from(&self.inner[0..LeftPublic::LEN]).unwrap() @@ -201,19 +138,19 @@ impl TryFrom<&'a[u8]> for Public { +impl TryFrom<&[u8]> for Public { type Error = (); fn try_from(data: &[u8]) -> Result { - if data.len() != LEFT_PLUS_RIGHT_LEN { - return Err(()) - } - let mut left : LeftPublic = data[0..LeftPublic::LEN].try_into()?; - let mut right : RightPublic = data[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into()?; + if data.len() != LEFT_PLUS_RIGHT_LEN { + return Err(()) + } + let left : LeftPublic = data[0..LeftPublic::LEN].try_into()?; + let right : RightPublic = data[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into()?; - let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; - inner.copy_from_slice(data); - Ok(Public { left, right, inner }) + let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; + inner.copy_from_slice(data); + Ok(Public { left, right, inner }) } } @@ -232,7 +169,7 @@ impl AsRef<[u8]> for Public { fn as_ref(&self) -> &[u8] { - &self.inner[..] + &self.inner[..] } } @@ -248,8 +185,8 @@ impl Self { - let mut left : LeftPublic = inner[0..LeftPublic::LEN].try_into().unwrap(); - let mut right : RightPublic = inner[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into().unwrap(); + let left : LeftPublic = inner[0..LeftPublic::LEN].try_into().unwrap(); + let right : RightPublic = inner[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into().unwrap(); Self { left, right, inner } } @@ -265,8 +202,8 @@ impl UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]> for Public { fn unchecked_from(data: [u8; LEFT_PLUS_RIGHT_LEN]) -> Self { - let mut left : LeftPublic = data[0..LeftPublic::LEN].try_into().unwrap(); - let mut right : RightPublic = data[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into().unwrap(); + let left : LeftPublic = data[0..LeftPublic::LEN].try_into().unwrap(); + let right : RightPublic = data[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into().unwrap(); Public { left: left, right: right, inner: data } } @@ -337,7 +274,7 @@ impl TryFrom<&'a[u8]> + AsRef<[u8]> {} impl TryFrom<&'a[u8]> + AsRef<[u8]>> SignatureBound for SignatureTrait {} @@ -365,15 +302,15 @@ impl TryFrom<&'a[u8]> for Signature where Signature: SignaturePair { +impl TryFrom<&[u8]> for Signature where Signature: SignaturePair { type Error = (); fn try_from(data: &[u8]) -> Result { if data.len() != LEFT_PLUS_RIGHT_LEN { return Err(()) } - let Ok(mut left) : Result = data[0..Self::LEFT_SIGNATURE_LEN].try_into() else { panic!("invalid signature") }; - let Ok(mut right) : Result= data[Self::LEFT_SIGNATURE_LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { panic!("invalid signature") }; + let Ok(left) : Result = data[0..Self::LEFT_SIGNATURE_LEN].try_into() else { panic!("invalid signature") }; + let Ok(right) : Result= data[Self::LEFT_SIGNATURE_LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { panic!("invalid signature") }; let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; inner[..Self::LEFT_SIGNATURE_LEN].copy_from_slice(left.as_ref()); @@ -411,18 +348,17 @@ impl Deserialize<'de> for Signature where -Signature: for<'a> TryFrom<&'a[u8]>{ +#[cfg(feature = "serde")] +impl<'de,LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize,> Deserialize<'de> for Signature where Signature: SignaturePair +{ fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let signature_hex = array_bytes::hex2bytes(&String::deserialize(deserializer)?) .map_err(|e| de::Error::custom(format!("{:?}", e)))?; - let sighex_ref = signature_hex.as_ref(); - Signature::try_from(sighex_ref) - .map_err(|e| de::Error::custom(format!("Error in converting deserialized data into signature"))) + Signature::::try_from(signature_hex.as_ref()) + .map_err(|e| de::Error::custom(format!("Error in converting deserialized data into signature: {:?}", e))) } } @@ -447,8 +383,8 @@ impl UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]> for Signature where Signature: SignaturePair { fn unchecked_from(data: [u8; LEFT_PLUS_RIGHT_LEN]) -> Self { - let Ok(mut left) = data[0..Self::LEFT_SIGNATURE_LEN].try_into() else { panic!("invalid signature") }; - let Ok(mut right) = data[Self::LEFT_SIGNATURE_LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { panic!("invalid signature") }; + let Ok(left) = data[0..Self::LEFT_SIGNATURE_LEN].try_into() else { panic!("invalid signature") }; + let Ok(right) = data[Self::LEFT_SIGNATURE_LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { panic!("invalid signature") }; Signature { left, right, inner: data } } @@ -467,15 +403,7 @@ pub struct Pair: CryptoType, Signature: SignaturePair, - LeftPair::Seed: SeedBound, - RightPair::Seed: SeedBound, -Seed: SeedBound, + LeftPair::Seed: From<[u8; SECURE_SEED_LEN]> + Into<[u8; SECURE_SEED_LEN]>, + RightPair::Seed: From<[u8; SECURE_SEED_LEN]> + Into<[u8; SECURE_SEED_LEN]>, { - type Seed = Seed; + type Seed = Seed; type Public = Public; type Signature = Signature; fn from_seed_slice(seed_slice: &[u8]) -> Result { - if seed_slice.len() != Self::RIGHT_SEED_LEN + Self::LEFT_SEED_LEN { + if seed_slice.len() != SECURE_SEED_LEN { return Err(SecretStringError::InvalidSeedLength) } - let left = LeftPair::from_seed_slice(&seed_slice[0..Self::LEFT_SEED_LEN])?; - let right = RightPair::from_seed_slice(&seed_slice[Self::LEFT_SEED_LEN..Self::RIGHT_SEED_LEN + Self::LEFT_SEED_LEN])?; + let left = LeftPair::from_seed_slice(&seed_slice)?; + let right = RightPair::from_seed_slice(&seed_slice)?; Ok(Pair { left, right }) } @@ -512,47 +439,47 @@ Seed: SeedBound, seed: Option, ) -> Result<(Self, Option), DeriveError> { - let seed_left_right = match seed { - Some(seed) => (Some(seed.left), Some(seed.right)), - None => (None, None), + let (left_seed_option, right_seed_option) = match seed { + Some(seed) => { + let (left_seed, right_seed): (LeftPair::Seed, RightPair::Seed) = (seed.clone().into(), seed.into()); + (Some(left_seed), Some(right_seed)) + }, + None => (None, None) }; - + let left_path: Vec<_> = path.map(|p|p.clone()).collect(); let right_path = left_path.clone(); - let derived_left = self.left.derive(left_path.into_iter(), seed_left_right.0)?; - let derived_right = self.right.derive(right_path.into_iter(), seed_left_right.1)?; - - let optional_seed = match (derived_left.1, derived_right.1) { - (Some(seed_left), Some(seed_right)) => { - let mut inner = [0u8; DOUBLE_SEED_LEN]; - inner[..Self::LEFT_SEED_LEN].copy_from_slice(seed_left.as_ref()); - inner[Self::LEFT_SEED_LEN..Self::LEFT_SEED_LEN + Self::RIGHT_SEED_LEN].copy_from_slice(seed_right.as_ref()); - Some(Self::Seed{left: seed_left, right: seed_right, inner: inner})}, - _ => None, - - }; - // Some(seed) => (LeftPair::from_seed_slice(&seed).ok().map(|p|p.to_raw_vec()), RightPair::from_seed_slice(&seed).ok().map(|p| p.to_raw_vec())), - // None => (None, None), - // }; + let derived_left = self.left.derive(left_path.into_iter(), left_seed_option)?; + let derived_right = self.right.derive(right_path.into_iter(), right_seed_option)?; + + let optional_seed : Option<[u8; SECURE_SEED_LEN]> = match (derived_left.1, derived_right.1) { + (Some(seed_left), Some(seed_right)) => { + if seed_left.as_ref() == seed_right.as_ref() + { + Some(seed_left.into()) + } else { + None + } + }, + _=> None, + }; Ok((Self{left: derived_left.0, right: derived_right.0}, optional_seed)) } fn public(&self) -> Self::Public { let mut raw = [0u8; PUBLIC_KEY_LEN]; let left_pub = self.left.public(); - let right_pub = self.right.public(); // let pk = DoublePublicKeyScheme::into_double_public_key(&self.0).to_bytes(); - raw[..LeftPair::Public::LEN].copy_from_slice(left_pub.as_ref()); + let right_pub = self.right.public(); + raw[..LeftPair::Public::LEN].copy_from_slice(left_pub.as_ref()); raw[LeftPair::Public::LEN..].copy_from_slice(right_pub.as_ref()); Self::Public::unchecked_from(raw) - //Public{left: left_pub, right: right_pub, inner: raw} } fn sign(&self, message: &[u8]) -> Self::Signature { - let mut mutable_self = self.clone(); let mut r: [u8; SIGNATURE_LEN] = [0u8; SIGNATURE_LEN]; - r[..Self::LEFT_SIGNATURE_LEN].copy_from_slice(self.left.sign(message).as_ref()); - r[Self::LEFT_SIGNATURE_LEN..].copy_from_slice(self.right.sign(message).as_ref()); + r[..Self::Signature::LEFT_SIGNATURE_LEN].copy_from_slice(self.left.sign(message).as_ref()); + r[Self::Signature::LEFT_SIGNATURE_LEN..].copy_from_slice(self.right.sign(message).as_ref()); Self::Signature::unchecked_from(r) } @@ -563,20 +490,19 @@ Seed: SeedBound, LeftPair::verify(&sig.left, message, &pubkey.left) && RightPair::verify(&sig.right, vec_message, &pubkey.right) } - /// Get the seed for this key. + /// Get the seed/secret key for each key and then concatenate them. fn to_raw_vec(&self) -> Vec { [self.left.to_raw_vec(), self.right.to_raw_vec()].concat() } } - -// Test set exercising the BLS12-377 implementation +// Test set exercising the (ECDSA, BLS12-377) implementation #[cfg(test)] mod test { use super::*; use crate::crypto::DEV_PHRASE; - use ecdsa_n_bls377::{Pair, Signature, Seed}; + use ecdsa_n_bls377::{Pair, Signature}; use hex_literal::hex; @@ -590,149 +516,147 @@ mod test { ); } - #[test] + #[test] fn seed_and_derive_should_work() { - let seed_left = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); - let seed_right = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f00"); - let pair = Pair::from_seed(&([seed_left,seed_right].concat()[..].try_into().unwrap())); - // we are using hash to field so this is not going to work - // assert_eq!(pair.seed(), seed); - let path = vec![DeriveJunction::Hard([0u8; 32])]; - let derived = pair.derive(path.into_iter(), None).ok().unwrap().0; - assert_eq!( - derived.to_raw_vec(), - [hex!("b8eefc4937200a8382d00050e050ced2d4ab72cc2ef1b061477afb51564fdd61"), hex!("a4f2269333b3e87c577aa00c4a2cd650b3b30b2e8c286a47c251279ff3a26e0d")].concat() - ); - } + let seed_for_right_and_left = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); + let pair = Pair::from_seed(&seed_for_right_and_left); + // we are using hash to field so this is not going to work + // assert_eq!(pair.seed(), seed); + let path = vec![DeriveJunction::Hard([0u8; 32])]; + let derived = pair.derive(path.into_iter(), None).ok().unwrap().0; + assert_eq!( + derived.to_raw_vec(), + [hex!("b8eefc4937200a8382d00050e050ced2d4ab72cc2ef1b061477afb51564fdd61"), hex!("3a0626d095148813cd1642d38254f1cfff7eb8cc1a2fc83b2a135377c3554c12")].concat() + ); + } - #[test] - fn test_vector_should_work() { - let seed_left = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); - let seed_right = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); - let pair = Pair::from_seed(&([seed_left,seed_right].concat()[..].try_into().unwrap())); - let public = pair.public(); - assert_eq!( - public, - Public::unchecked_from( - hex!("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd917a84ca8ce4c37c93c95ecee6a3c0c9a7b9c225093cf2f12dc4f69cbfb847ef9424a18f5755d5a742247d386ff2aabb806bcf160eff31293ea9616976628f77266c8a8cc1d8753be04197bd6cdd8c5c87a148f782c4c1568d599b48833fd539001e580cff64bbc71850605433fcd051f3afc3b74819786f815ffb5272030a8d03e5df61e6183f8fd8ea85f26defa83400" + #[test] + fn test_vector_should_work() { + let seed_left_and_right = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); + let pair = Pair::from_seed(&([seed_left_and_right].concat()[..].try_into().unwrap())); + let public = pair.public(); + assert_eq!( + public, + Public::unchecked_from( + hex!("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd917a84ca8ce4c37c93c95ecee6a3c0c9a7b9c225093cf2f12dc4f69cbfb847ef9424a18f5755d5a742247d386ff2aabb806bcf160eff31293ea9616976628f77266c8a8cc1d8753be04197bd6cdd8c5c87a148f782c4c1568d599b48833fd539001e580cff64bbc71850605433fcd051f3afc3b74819786f815ffb5272030a8d03e5df61e6183f8fd8ea85f26defa83400" ), - ), - ); - let message = b""; - let signature = hex!("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00d1e3013161991e142d8751017d4996209c2ff8a9ee160f373733eda3b4b785ba6edce9f45f87104bbe07aa6aa6eb2780aa705efb2c13d3b317d6409d159d23bdc7cdd5c2a832d1551cf49d811d49c901495e527dbd532e3a462335ce2686009104aba7bc11c5b22be78f3198d2727a0b"); - let signature = Signature::unchecked_from(signature); - assert!(pair.sign(&message[..]) == signature); - assert!(Pair::verify(&signature, &message[..], &public)); - } + ), + ); + let message = b""; + let signature = hex!("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00d1e3013161991e142d8751017d4996209c2ff8a9ee160f373733eda3b4b785ba6edce9f45f87104bbe07aa6aa6eb2780aa705efb2c13d3b317d6409d159d23bdc7cdd5c2a832d1551cf49d811d49c901495e527dbd532e3a462335ce2686009104aba7bc11c5b22be78f3198d2727a0b"); + let signature = Signature::unchecked_from(signature); + assert!(pair.sign(&message[..]) == signature); + assert!(Pair::verify(&signature, &message[..], &public)); + } - #[test] - fn test_vector_by_string_should_work() { - let pair = Pair::from_string("0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f609d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", - None, - ) - .unwrap(); - let public = pair.public(); - assert_eq!( - public, - Public::unchecked_from( - hex!("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd916dc6be608fab3c6bd894a606be86db346cc170db85c733853a371f3db54ae1b12052c0888d472760c81b537572a26f00db865e5963aef8634f9917571c51b538b564b2a9ceda938c8b930969ee3b832448e08e33a79e9ddd28af419a3ce45300f5dbc768b067781f44f3fe05a19e6b07b1c4196151ec3f8ea37e4f89a8963030d2101e931276bb9ebe1f20102239d780" + #[test] + fn test_vector_by_string_should_work() { + let pair = Pair::from_string("0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", + None, + ) + .unwrap(); + let public = pair.public(); + assert_eq!( + public, + Public::unchecked_from( + hex!("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd916dc6be608fab3c6bd894a606be86db346cc170db85c733853a371f3db54ae1b12052c0888d472760c81b537572a26f00db865e5963aef8634f9917571c51b538b564b2a9ceda938c8b930969ee3b832448e08e33a79e9ddd28af419a3ce45300f5dbc768b067781f44f3fe05a19e6b07b1c4196151ec3f8ea37e4f89a8963030d2101e931276bb9ebe1f20102239d780" ), - ), - ); - let message = b""; - let signature = hex!("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00bbb395bbdee1a35930912034f5fde3b36df2835a0536c865501b0675776a1d5931a3bea2e66eff73b2546c6af2061a8019223e4ebbbed661b2538e0f5823f2c708eb89c406beca8fcb53a5c13dbc7c0c42e4cf2be2942bba96ea29297915a06bd2b1b979c0e2ac8fd4ec684a6b5d110c"); - let signature = Signature::unchecked_from(signature); - assert!(pair.sign(&message[..]) == signature); - assert!(Pair::verify(&signature, &message[..], &public)); - } + ), + ); + let message = b""; + let signature = hex!("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00bbb395bbdee1a35930912034f5fde3b36df2835a0536c865501b0675776a1d5931a3bea2e66eff73b2546c6af2061a8019223e4ebbbed661b2538e0f5823f2c708eb89c406beca8fcb53a5c13dbc7c0c42e4cf2be2942bba96ea29297915a06bd2b1b979c0e2ac8fd4ec684a6b5d110c"); + let signature = Signature::unchecked_from(signature); + assert!(pair.sign(&message[..]) == signature); + assert!(Pair::verify(&signature, &message[..], &public)); + } #[test] - fn generated_pair_should_work() { - let (pair, _) = Pair::generate(); - let public = pair.public(); - let message = b"Something important"; - let signature = pair.sign(&message[..]); - assert!(Pair::verify(&signature, &message[..], &public)); - assert!(!Pair::verify(&signature, b"Something else", &public)); - } + fn generated_pair_should_work() { + let (pair, _) = Pair::generate(); + let public = pair.public(); + let message = b"Something important"; + let signature = pair.sign(&message[..]); + assert!(Pair::verify(&signature, &message[..], &public)); + assert!(!Pair::verify(&signature, b"Something else", &public)); + } #[test] - fn seeded_pair_should_work() { - let pair = Pair::from_seed(&(b"1234567890123456789012345678901212345678901234567890123456789012".as_slice().try_into().unwrap())); - let public = pair.public(); - assert_eq!( - public, - Public::unchecked_from( - hex!("035676109c54b9a16d271abeb4954316a40a32bcce023ac14c8e26e958aa68fba9754d2f2bbfa67df54d7e0e951979a18a1e0f45948857752cc2bac6bbb0b1d05e8e48bcc453920bf0c4bbd5993212480112a1fb433f04d74af0a8b700d93dc957ab3207f8d071e948f5aca1a7632c00bdf6d06be05b43e2e6216dccc8a5d55a0071cb2313cfd60b7e9114619cd17c06843b352f0b607a99122f6651df8f02e1ad3697bd208e62af047ddd7b942ba80080") + fn seeded_pair_should_work() { + let pair = Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap())); + let public = pair.public(); + assert_eq!( + public, + Public::unchecked_from( + hex!("035676109c54b9a16d271abeb4954316a40a32bcce023ac14c8e26e958aa68fba9754d2f2bbfa67df54d7e0e951979a18a1e0f45948857752cc2bac6bbb0b1d05e8e48bcc453920bf0c4bbd5993212480112a1fb433f04d74af0a8b700d93dc957ab3207f8d071e948f5aca1a7632c00bdf6d06be05b43e2e6216dccc8a5d55a0071cb2313cfd60b7e9114619cd17c06843b352f0b607a99122f6651df8f02e1ad3697bd208e62af047ddd7b942ba80080") ), - ); - let message = - hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000" - ); - let signature = pair.sign(&message[..]); - println!("Correct signature: {:?}", signature); - assert!(Pair::verify(&signature, &message[..], &public)); - assert!(!Pair::verify(&signature, "Other message", &public)); - } + ); + let message = + hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000" + ); + let signature = pair.sign(&message[..]); + println!("Correct signature: {:?}", signature); + assert!(Pair::verify(&signature, &message[..], &public)); + assert!(!Pair::verify(&signature, "Other message", &public)); + } - #[test] - fn generate_with_phrase_recovery_possible() { - let (pair1, phrase, _) = Pair::generate_with_phrase(None); - let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap(); + #[test] + fn generate_with_phrase_recovery_possible() { + let (pair1, phrase, _) = Pair::generate_with_phrase(None); + let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap(); - assert_eq!(pair1.public(), pair2.public()); - } + assert_eq!(pair1.public(), pair2.public()); + } - #[test] - fn generate_with_password_phrase_recovery_possible() { - let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password")); - let (pair2, _) = Pair::from_phrase(&phrase, Some("password")).unwrap(); + #[test] + fn generate_with_password_phrase_recovery_possible() { + let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password")); + let (pair2, _) = Pair::from_phrase(&phrase, Some("password")).unwrap(); - assert_eq!(pair1.public(), pair2.public()); - } + assert_eq!(pair1.public(), pair2.public()); + } - #[test] - fn password_does_something() { - let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password")); - let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap(); + #[test] + fn password_does_something() { + let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password")); + let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap(); - assert_ne!(pair1.public(), pair2.public()); - } + assert_ne!(pair1.public(), pair2.public()); + } - #[test] + #[test] fn ss58check_roundtrip_works() { - let pair = Pair::from_seed(&(b"1234567890123456789012345678901212345678901234567890123456789012".as_slice().try_into().unwrap())); - let public = pair.public(); - let s = public.to_ss58check(); - println!("Correct: {}", s); - let cmp = Public::from_ss58check(&s).unwrap(); - assert_eq!(cmp, public); - } + let pair = Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap())); + let public = pair.public(); + let s = public.to_ss58check(); + println!("Correct: {}", s); + let cmp = Public::from_ss58check(&s).unwrap(); + assert_eq!(cmp, public); + } - #[test] - fn signature_serialization_works() { - let pair = Pair::from_seed(&(b"1234567890123456789012345678901212345678901234567890123456789012".as_slice().try_into().unwrap())); - let message = b"Something important"; - let signature = pair.sign(&message[..]); - - let serialized_signature = serde_json::to_string(&signature).unwrap(); - println!("{:?} -- {:}", signature.inner, serialized_signature); - // Signature is 177 bytes, hexify * 2, so 354 chars + 2 quote charsy - assert_eq!(serialized_signature.len(), 356); - let signature = serde_json::from_str(&serialized_signature).unwrap(); - assert!(Pair::verify(&signature, &message[..], &pair.public())); - } + #[test] + fn signature_serialization_works() { + let pair = Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap())); + let message = b"Something important"; + let signature = pair.sign(&message[..]); + + let serialized_signature = serde_json::to_string(&signature).unwrap(); + println!("{:?} -- {:}", signature.inner, serialized_signature); + // Signature is 177 bytes, hexify * 2, so 354 chars + 2 quote charsy + assert_eq!(serialized_signature.len(), 356); + let signature = serde_json::from_str(&serialized_signature).unwrap(); + assert!(Pair::verify(&signature, &message[..], &pair.public())); + } - #[test] - fn signature_serialization_doesnt_panic() { - fn deserialize_signature(text: &str) -> Result { - serde_json::from_str(text) - } - assert!(deserialize_signature("Not valid json.").is_err()); - assert!(deserialize_signature("\"Not an actual signature.\"").is_err()); - // Poorly-sized - assert!(deserialize_signature("\"abc123\"").is_err()); - } + #[test] + fn signature_serialization_doesnt_panic() { + fn deserialize_signature(text: &str) -> Result { + serde_json::from_str(text) + } + assert!(deserialize_signature("Not valid json.").is_err()); + assert!(deserialize_signature("\"Not an actual signature.\"").is_err()); + // Poorly-sized + assert!(deserialize_signature("\"abc123\"").is_err()); + } } From 83469f77f5faee9e83d45137faa45260c1e05290 Mon Sep 17 00:00:00 2001 From: Skalman Date: Mon, 25 Sep 2023 12:12:37 -0400 Subject: [PATCH 13/13] cargo fmt --- primitives/core/src/paired_crypto.rs | 882 ++++++++++++++++----------- 1 file changed, 529 insertions(+), 353 deletions(-) diff --git a/primitives/core/src/paired_crypto.rs b/primitives/core/src/paired_crypto.rs index 872dd64d9381b..968930b73d511 100644 --- a/primitives/core/src/paired_crypto.rs +++ b/primitives/core/src/paired_crypto.rs @@ -37,53 +37,51 @@ use sp_std::convert::TryFrom; /// ECDSA and BLS-377 paired crypto scheme #[cfg(feature = "bls-experimental")] pub mod ecdsa_n_bls377 { - use crate::crypto::{CryptoTypeId}; - use crate::{ecdsa, bls377}; - - /// An identifier used to match public keys against BLS12-377 keys - pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecb7"); - - const PUBLIC_KEY_LEN :usize = 33 + crate::bls::PUBLIC_KEY_SERIALIZED_SIZE; - const LEFT_SIGNATURE_LEN :usize = 65; - const RIGHT_SIGNATURE_LEN :usize = crate::bls::SIGNATURE_SERIALIZED_SIZE; - const SIGNATURE_LEN: usize = LEFT_SIGNATURE_LEN + RIGHT_SIGNATURE_LEN; - - /// (ECDSA, BLS12-377) key-pair pair. - #[cfg(feature = "full_crypto")] - pub type Pair = super::Pair; + use crate::crypto::CryptoTypeId; + use crate::{bls377, ecdsa}; + + /// An identifier used to match public keys against BLS12-377 keys + pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecb7"); + + const PUBLIC_KEY_LEN: usize = 33 + crate::bls::PUBLIC_KEY_SERIALIZED_SIZE; + const LEFT_SIGNATURE_LEN: usize = 65; + const RIGHT_SIGNATURE_LEN: usize = crate::bls::SIGNATURE_SERIALIZED_SIZE; + const SIGNATURE_LEN: usize = LEFT_SIGNATURE_LEN + RIGHT_SIGNATURE_LEN; + + /// (ECDSA, BLS12-377) key-pair pair. + #[cfg(feature = "full_crypto")] + pub type Pair = super::Pair; /// (ECDSA, BLS12-377) public key pair. - pub type Public = super::Public; + pub type Public = super::Public; /// (ECDSA, BLS12-377) signature pair. - pub type Signature = super::Signature; - - impl super::SignaturePair for Signature { - const LEFT_SIGNATURE_LEN: usize = LEFT_SIGNATURE_LEN; - const RIGHT_SIGNATURE_LEN: usize = RIGHT_SIGNATURE_LEN; - const LEFT_PLUS_RIGHT_LEN: usize = SIGNATURE_LEN; - } - - #[cfg(feature = "full_crypto")] - impl super::DoublePair for Pair{ - const PUBLIC_KEY_LEN: usize = PUBLIC_KEY_LEN; - const SIGNATURE_LEN: usize = SIGNATURE_LEN; - } - - impl super::CryptoType for Public - { - #[cfg(feature = "full_crypto")] - type Pair = Pair; - } - - impl super::CryptoType for Signature { - #[cfg(feature = "full_crypto")] - type Pair = Pair; - } - - #[cfg(feature = "full_crypto")] - impl super::CryptoType for Pair{ - type Pair = Pair; - } + pub type Signature = super::Signature; + + impl super::SignaturePair for Signature { + const LEFT_SIGNATURE_LEN: usize = LEFT_SIGNATURE_LEN; + const RIGHT_SIGNATURE_LEN: usize = RIGHT_SIGNATURE_LEN; + const LEFT_PLUS_RIGHT_LEN: usize = SIGNATURE_LEN; + } + + #[cfg(feature = "full_crypto")] + impl super::DoublePair for Pair { + const PUBLIC_KEY_LEN: usize = PUBLIC_KEY_LEN; + const SIGNATURE_LEN: usize = SIGNATURE_LEN; + } + impl super::CryptoType for Public { + #[cfg(feature = "full_crypto")] + type Pair = Pair; + } + + impl super::CryptoType for Signature { + #[cfg(feature = "full_crypto")] + type Pair = Pair; + } + + #[cfg(feature = "full_crypto")] + impl super::CryptoType for Pair { + type Pair = Pair; + } } /// currently only supporting sub-schemes whose seed is a 32-bytes array. @@ -98,19 +96,43 @@ const SECURE_SEED_LEN: usize = 32; #[cfg(feature = "full_crypto")] type Seed = [u8; SECURE_SEED_LEN]; - /// trait characterizing Public key which could be used as individual component of an `paired_crypto:Public` pair. -pub trait PublicKeyBound: TraitPublic + Sized + Derive + sp_std::hash::Hash + ByteArray + for<'a> TryFrom<&'a[u8]> + AsMut<[u8]> + CryptoType {} +pub trait PublicKeyBound: + TraitPublic + + Sized + + Derive + + sp_std::hash::Hash + + ByteArray + + for<'a> TryFrom<&'a [u8]> + + AsMut<[u8]> + + CryptoType +{ +} -impl TryFrom<&'a[u8]> + AsMut<[u8]> + CryptoType> PublicKeyBound for PublicKeyTrait {} +impl< + PublicKeyTrait: TraitPublic + + Sized + + Derive + + sp_std::hash::Hash + + ByteArray + + for<'a> TryFrom<&'a [u8]> + + AsMut<[u8]> + + CryptoType, + > PublicKeyBound for PublicKeyTrait +{ +} /// A public key. #[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq, PartialOrd, Ord)] #[scale_info(skip_type_params(T))] -pub struct Public { - left: LeftPublic, - right: RightPublic, - inner: [u8; LEFT_PLUS_RIGHT_LEN], +pub struct Public< + LeftPublic: PublicKeyBound, + RightPublic: PublicKeyBound, + const LEFT_PLUS_RIGHT_LEN: usize, +> { + left: LeftPublic, + right: RightPublic, + inner: [u8; LEFT_PLUS_RIGHT_LEN], } // We essentially could implement the following instead of storing left and right but we are going to end up copying and deserializing left and right, to perform any operation and that will take a hit on performance. @@ -123,57 +145,69 @@ pub struct Public sp_std::hash::Hash for Public { - fn hash(&self, state: &mut H) { - self.left.hash(state); - self.right.hash(state); +impl + sp_std::hash::Hash for Public +{ + fn hash(&self, state: &mut H) { + self.left.hash(state); + self.right.hash(state); } } -impl ByteArray for Public { - const LEN: usize = LEFT_PLUS_RIGHT_LEN; +impl + ByteArray for Public +{ + const LEN: usize = LEFT_PLUS_RIGHT_LEN; } -impl TryFrom<&[u8]> for Public { - type Error = (); - - fn try_from(data: &[u8]) -> Result { - if data.len() != LEFT_PLUS_RIGHT_LEN { - return Err(()) - } - let left : LeftPublic = data[0..LeftPublic::LEN].try_into()?; - let right : RightPublic = data[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into()?; - - let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; - inner.copy_from_slice(data); - Ok(Public { left, right, inner }) - - } +impl + TryFrom<&[u8]> for Public +{ + type Error = (); + + fn try_from(data: &[u8]) -> Result { + if data.len() != LEFT_PLUS_RIGHT_LEN { + return Err(()); + } + let left: LeftPublic = data[0..LeftPublic::LEN].try_into()?; + let right: RightPublic = data[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into()?; + + let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; + inner.copy_from_slice(data); + Ok(Public { left, right, inner }) + } } - -impl AsMut<[u8]> for Public { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.inner[..] - } + +impl + AsMut<[u8]> for Public +{ + fn as_mut(&mut self) -> &mut [u8] { + &mut self.inner[..] + } } -impl AsRef<[u8; LEFT_PLUS_RIGHT_LEN]> for Public { - fn as_ref(&self) -> &[u8; LEFT_PLUS_RIGHT_LEN] { +impl + AsRef<[u8; LEFT_PLUS_RIGHT_LEN]> for Public +{ + fn as_ref(&self) -> &[u8; LEFT_PLUS_RIGHT_LEN] { &self.inner - } + } } -impl AsRef<[u8]> for Public { - fn as_ref(&self) -> &[u8] { - &self.inner[..] - } +impl + AsRef<[u8]> for Public +{ + fn as_ref(&self) -> &[u8] { + &self.inner[..] + } } -impl PassByInner for Public { +impl + PassByInner for Public +{ type Inner = [u8; LEFT_PLUS_RIGHT_LEN]; fn into_inner(self) -> Self::Inner { @@ -185,33 +219,49 @@ impl Self { - let left : LeftPublic = inner[0..LeftPublic::LEN].try_into().unwrap(); - let right : RightPublic = inner[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into().unwrap(); + let left: LeftPublic = inner[0..LeftPublic::LEN].try_into().unwrap(); + let right: RightPublic = inner[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into().unwrap(); Self { left, right, inner } } } #[cfg(feature = "full_crypto")] -impl From> for Public where Pair : TraitPair>, - { +impl< + LeftPair: TraitPair, + RightPair: TraitPair, + LeftPublic: PublicKeyBound, + RightPublic: PublicKeyBound, + const LEFT_PLUS_RIGHT_PUBLIC_LEN: usize, + const SIGNATURE_LEN: usize, + > From> + for Public +where + Pair: + TraitPair>, +{ fn from(x: Pair) -> Self { x.public() } } -impl UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]> for Public { +impl + UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]> for Public +{ fn unchecked_from(data: [u8; LEFT_PLUS_RIGHT_LEN]) -> Self { - let left : LeftPublic = data[0..LeftPublic::LEN].try_into().unwrap(); - let right : RightPublic = data[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into().unwrap(); + let left: LeftPublic = data[0..LeftPublic::LEN].try_into().unwrap(); + let right: RightPublic = data[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN].try_into().unwrap(); - Public { left: left, right: right, inner: data } + Public { left, right, inner: data } } - } #[cfg(feature = "std")] -impl std::str::FromStr for Public where Public : CryptoType { +impl + std::str::FromStr for Public +where + Public: CryptoType, +{ type Err = crate::crypto::PublicError; fn from_str(s: &str) -> Result { @@ -220,14 +270,23 @@ impl std::fmt::Display for Public where Public : CryptoType { +impl + std::fmt::Display for Public +where + Public: CryptoType, +{ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", self.to_ss58check()) } } #[cfg(feature = "std")] -impl sp_std::fmt::Debug for Public where Public : CryptoType, [u8;LEFT_PLUS_RIGHT_LEN]: crate::hexdisplay::AsBytesRef { +impl + sp_std::fmt::Debug for Public +where + Public: CryptoType, + [u8; LEFT_PLUS_RIGHT_LEN]: crate::hexdisplay::AsBytesRef, +{ fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { let s = self.to_ss58check(); write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.inner), &s[0..8]) @@ -235,111 +294,173 @@ impl sp_std::fmt::Debug for Public { +impl + sp_std::fmt::Debug for Public +{ fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - - Ok(()) + Ok(()) } } #[cfg(feature = "std")] -impl Serialize for Public where Public : CryptoType { +impl + Serialize for Public +where + Public: CryptoType, +{ fn serialize(&self, serializer: S) -> Result where S: Serializer, - { - serializer.serialize_str(&self.to_ss58check()) - + { + serializer.serialize_str(&self.to_ss58check()) } } #[cfg(feature = "std")] -impl<'de, LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> Deserialize<'de> for Public where Public : CryptoType { +impl< + 'de, + LeftPublic: PublicKeyBound, + RightPublic: PublicKeyBound, + const LEFT_PLUS_RIGHT_LEN: usize, + > Deserialize<'de> for Public +where + Public: CryptoType, +{ fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, - { - Public::from_ss58check(&String::deserialize(deserializer)?) + { + Public::from_ss58check(&String::deserialize(deserializer)?) .map_err(|e| de::Error::custom(format!("{:?}", e))) - } } -impl TraitPublic for Public where Public : CryptoType {} +impl + TraitPublic for Public +where + Public: CryptoType, +{ +} -impl Derive for Public {} +impl + Derive for Public +{ +} #[cfg(not(feature = "full_crypto"))] -impl CryptoType for Public -{} - +impl< + LeftPublic: PublicKeyBound, + RightPublic: PublicKeyBound, + const LEFT_PLUS_RIGHT_PUBLIC_LEN: usize, + > CryptoType for Public +{ +} /// trait characterizing a signature which could be used as individual component of an `paired_crypto:Signature` pair. -pub trait SignatureBound: sp_std::hash::Hash + for<'a> TryFrom<&'a[u8]> + AsRef<[u8]> {} +pub trait SignatureBound: sp_std::hash::Hash + for<'a> TryFrom<&'a [u8]> + AsRef<[u8]> {} -impl TryFrom<&'a[u8]> + AsRef<[u8]>> SignatureBound for SignatureTrait {} +impl TryFrom<&'a [u8]> + AsRef<[u8]>> SignatureBound + for SignatureTrait +{ +} /// A pair of signatures of different types #[derive(Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq)] #[scale_info(skip_type_params(T))] -pub struct Signature { - left: LeftSignature, - right: RightSignature, - inner: [u8; LEFT_PLUS_RIGHT_LEN], +pub struct Signature< + LeftSignature: SignatureBound, + RightSignature: SignatureBound, + const LEFT_PLUS_RIGHT_LEN: usize, +> { + left: LeftSignature, + right: RightSignature, + inner: [u8; LEFT_PLUS_RIGHT_LEN], } trait SignaturePair { - const LEFT_SIGNATURE_LEN: usize; - const RIGHT_SIGNATURE_LEN: usize; - const LEFT_PLUS_RIGHT_LEN: usize; + const LEFT_SIGNATURE_LEN: usize; + const RIGHT_SIGNATURE_LEN: usize; + const LEFT_PLUS_RIGHT_LEN: usize; } #[cfg(feature = "full_crypto")] -impl sp_std::hash::Hash for Signature { - fn hash(&self, state: &mut H) { - self.left.hash(state); - self.right.hash(state); +impl< + LeftSignature: SignatureBound, + RightSignature: SignatureBound, + const LEFT_PLUS_RIGHT_LEN: usize, + > sp_std::hash::Hash for Signature +{ + fn hash(&self, state: &mut H) { + self.left.hash(state); + self.right.hash(state); } } -impl TryFrom<&[u8]> for Signature where Signature: SignaturePair { - type Error = (); - - fn try_from(data: &[u8]) -> Result { - if data.len() != LEFT_PLUS_RIGHT_LEN { - return Err(()) - } - let Ok(left) : Result = data[0..Self::LEFT_SIGNATURE_LEN].try_into() else { panic!("invalid signature") }; - let Ok(right) : Result= data[Self::LEFT_SIGNATURE_LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { panic!("invalid signature") }; +impl< + LeftSignature: SignatureBound, + RightSignature: SignatureBound, + const LEFT_PLUS_RIGHT_LEN: usize, + > TryFrom<&[u8]> for Signature +where + Signature: SignaturePair, +{ + type Error = (); - let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; - inner[..Self::LEFT_SIGNATURE_LEN].copy_from_slice(left.as_ref()); - inner[Self::LEFT_SIGNATURE_LEN..].copy_from_slice(right.as_ref()); + fn try_from(data: &[u8]) -> Result { + if data.len() != LEFT_PLUS_RIGHT_LEN { + return Err(()); + } + let Ok(left) : Result = data[0..Self::LEFT_SIGNATURE_LEN].try_into() else { panic!("invalid signature") }; + let Ok(right) : Result= data[Self::LEFT_SIGNATURE_LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { panic!("invalid signature") }; - Ok(Signature { left, right, inner }) + let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; + inner[..Self::LEFT_SIGNATURE_LEN].copy_from_slice(left.as_ref()); + inner[Self::LEFT_SIGNATURE_LEN..].copy_from_slice(right.as_ref()); - } + Ok(Signature { left, right, inner }) + } } - -impl AsMut<[u8]> for Signature { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.inner[..] - } + +impl< + LeftSignature: SignatureBound, + RightSignature: SignatureBound, + const LEFT_PLUS_RIGHT_LEN: usize, + > AsMut<[u8]> for Signature +{ + fn as_mut(&mut self) -> &mut [u8] { + &mut self.inner[..] + } } -impl AsRef<[u8; LEFT_PLUS_RIGHT_LEN]> for Signature { - fn as_ref(&self) -> &[u8; LEFT_PLUS_RIGHT_LEN] { +impl< + LeftSignature: SignatureBound, + RightSignature: SignatureBound, + const LEFT_PLUS_RIGHT_LEN: usize, + > AsRef<[u8; LEFT_PLUS_RIGHT_LEN]> + for Signature +{ + fn as_ref(&self) -> &[u8; LEFT_PLUS_RIGHT_LEN] { &self.inner - } + } } -impl AsRef<[u8]> for Signature { - fn as_ref(&self) -> &[u8] { - &self.inner[..] - } +impl< + LeftSignature: SignatureBound, + RightSignature: SignatureBound, + const LEFT_PLUS_RIGHT_LEN: usize, + > AsRef<[u8]> for Signature +{ + fn as_ref(&self) -> &[u8] { + &self.inner[..] + } } #[cfg(feature = "std")] -impl Serialize for Signature { +impl< + LeftSignature: SignatureBound, + RightSignature: SignatureBound, + const LEFT_PLUS_RIGHT_LEN: usize, + > Serialize for Signature +{ fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -349,7 +470,14 @@ impl Deserialize<'de> for Signature where Signature: SignaturePair +impl< + 'de, + LeftSignature: SignatureBound, + RightSignature: SignatureBound, + const LEFT_PLUS_RIGHT_LEN: usize, + > Deserialize<'de> for Signature +where + Signature: SignaturePair, { fn deserialize(deserializer: D) -> Result where @@ -357,19 +485,40 @@ impl<'de,LeftSignature: SignatureBound, RightSignature: SignatureBound, const LE { let signature_hex = array_bytes::hex2bytes(&String::deserialize(deserializer)?) .map_err(|e| de::Error::custom(format!("{:?}", e)))?; - Signature::::try_from(signature_hex.as_ref()) - .map_err(|e| de::Error::custom(format!("Error in converting deserialized data into signature: {:?}", e))) + Signature::::try_from( + signature_hex.as_ref(), + ) + .map_err(|e| { + de::Error::custom(format!( + "Error in converting deserialized data into signature: {:?}", + e + )) + }) } } -impl From> for [u8; LEFT_PLUS_RIGHT_LEN] +impl< + LeftSignature: SignatureBound, + RightSignature: SignatureBound, + const LEFT_PLUS_RIGHT_LEN: usize, + > From> + for [u8; LEFT_PLUS_RIGHT_LEN] { - fn from(signature: Signature) -> [u8; LEFT_PLUS_RIGHT_LEN] { + fn from( + signature: Signature, + ) -> [u8; LEFT_PLUS_RIGHT_LEN] { signature.inner } } -impl sp_std::fmt::Debug for Signature where [u8;LEFT_PLUS_RIGHT_LEN]: crate::hexdisplay::AsBytesRef{ +impl< + LeftSignature: SignatureBound, + RightSignature: SignatureBound, + const LEFT_PLUS_RIGHT_LEN: usize, + > sp_std::fmt::Debug for Signature +where + [u8; LEFT_PLUS_RIGHT_LEN]: crate::hexdisplay::AsBytesRef, +{ #[cfg(feature = "std")] fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.inner)) @@ -381,113 +530,134 @@ impl UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]> for Signature where Signature: SignaturePair { +impl< + LeftSignature: SignatureBound, + RightSignature: SignatureBound, + const LEFT_PLUS_RIGHT_LEN: usize, + > UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]> + for Signature +where + Signature: SignaturePair, +{ fn unchecked_from(data: [u8; LEFT_PLUS_RIGHT_LEN]) -> Self { - let Ok(left) = data[0..Self::LEFT_SIGNATURE_LEN].try_into() else { panic!("invalid signature") }; - let Ok(right) = data[Self::LEFT_SIGNATURE_LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { panic!("invalid signature") }; + let Ok(left) = data[0..Self::LEFT_SIGNATURE_LEN].try_into() else { panic!("invalid signature") }; + let Ok(right) = data[Self::LEFT_SIGNATURE_LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { panic!("invalid signature") }; - Signature { left, right, inner: data } + Signature { left, right, inner: data } } } /// A key pair. #[cfg(feature = "full_crypto")] #[derive(Clone)] -pub struct Pair -{ - left: LeftPair, - right: RightPair, - +pub struct Pair< + LeftPair: TraitPair, + RightPair: TraitPair, + const PUBLIC_KEY_LEN: usize, + const SIGNATURE_LEN: usize, +> { + left: LeftPair, + right: RightPair, } - trait DoublePair { - const PUBLIC_KEY_LEN: usize; - const SIGNATURE_LEN: usize; + const PUBLIC_KEY_LEN: usize; + const SIGNATURE_LEN: usize; } #[cfg(feature = "full_crypto")] -impl Pair { +impl< + LeftPair: TraitPair, + RightPair: TraitPair, + const PUBLIC_KEY_LEN: usize, + const SIGNATURE_LEN: usize, + > Pair +{ } #[cfg(feature = "full_crypto")] -impl TraitPair for Pair where - Pair: DoublePair + CryptoType, - LeftPair::Signature: SignatureBound, - RightPair::Signature: SignatureBound, -Public: CryptoType, -Signature: SignaturePair, - LeftPair::Seed: From<[u8; SECURE_SEED_LEN]> + Into<[u8; SECURE_SEED_LEN]>, - RightPair::Seed: From<[u8; SECURE_SEED_LEN]> + Into<[u8; SECURE_SEED_LEN]>, +impl< + LeftPair: TraitPair, + RightPair: TraitPair, + const PUBLIC_KEY_LEN: usize, + const SIGNATURE_LEN: usize, + > TraitPair for Pair +where + Pair: DoublePair + CryptoType, + LeftPair::Signature: SignatureBound, + RightPair::Signature: SignatureBound, + Public: CryptoType, + Signature: SignaturePair, + LeftPair::Seed: From<[u8; SECURE_SEED_LEN]> + Into<[u8; SECURE_SEED_LEN]>, + RightPair::Seed: From<[u8; SECURE_SEED_LEN]> + Into<[u8; SECURE_SEED_LEN]>, { type Seed = Seed; type Public = Public; type Signature = Signature; fn from_seed_slice(seed_slice: &[u8]) -> Result { - if seed_slice.len() != SECURE_SEED_LEN { - return Err(SecretStringError::InvalidSeedLength) - } - let left = LeftPair::from_seed_slice(&seed_slice)?; - let right = RightPair::from_seed_slice(&seed_slice)?; - Ok(Pair { left, right }) + if seed_slice.len() != SECURE_SEED_LEN { + return Err(SecretStringError::InvalidSeedLength); + } + let left = LeftPair::from_seed_slice(&seed_slice)?; + let right = RightPair::from_seed_slice(&seed_slice)?; + Ok(Pair { left, right }) } fn derive>( - &self, - path: Iter, - seed: Option, + &self, + path: Iter, + seed: Option, ) -> Result<(Self, Option), DeriveError> { - - let (left_seed_option, right_seed_option) = match seed { - Some(seed) => { - let (left_seed, right_seed): (LeftPair::Seed, RightPair::Seed) = (seed.clone().into(), seed.into()); - (Some(left_seed), Some(right_seed)) - }, - None => (None, None) - }; - - let left_path: Vec<_> = path.map(|p|p.clone()).collect(); - let right_path = left_path.clone(); - let derived_left = self.left.derive(left_path.into_iter(), left_seed_option)?; - let derived_right = self.right.derive(right_path.into_iter(), right_seed_option)?; - - let optional_seed : Option<[u8; SECURE_SEED_LEN]> = match (derived_left.1, derived_right.1) { - (Some(seed_left), Some(seed_right)) => { - if seed_left.as_ref() == seed_right.as_ref() - { - Some(seed_left.into()) - } else { - None - } - }, - _=> None, - - }; - Ok((Self{left: derived_left.0, right: derived_right.0}, optional_seed)) - } + let (left_seed_option, right_seed_option) = match seed { + Some(seed) => { + let (left_seed, right_seed): (LeftPair::Seed, RightPair::Seed) = + (seed.clone().into(), seed.into()); + (Some(left_seed), Some(right_seed)) + }, + None => (None, None), + }; + + let left_path: Vec<_> = path.map(|p| p.clone()).collect(); + let right_path = left_path.clone(); + let derived_left = self.left.derive(left_path.into_iter(), left_seed_option)?; + let derived_right = self.right.derive(right_path.into_iter(), right_seed_option)?; + + let optional_seed: Option<[u8; SECURE_SEED_LEN]> = match (derived_left.1, derived_right.1) { + (Some(seed_left), Some(seed_right)) => { + if seed_left.as_ref() == seed_right.as_ref() { + Some(seed_left.into()) + } else { + None + } + }, + _ => None, + }; + Ok((Self { left: derived_left.0, right: derived_right.0 }, optional_seed)) + } fn public(&self) -> Self::Public { - let mut raw = [0u8; PUBLIC_KEY_LEN]; - let left_pub = self.left.public(); - let right_pub = self.right.public(); - raw[..LeftPair::Public::LEN].copy_from_slice(left_pub.as_ref()); - raw[LeftPair::Public::LEN..].copy_from_slice(right_pub.as_ref()); - Self::Public::unchecked_from(raw) + let mut raw = [0u8; PUBLIC_KEY_LEN]; + let left_pub = self.left.public(); + let right_pub = self.right.public(); + raw[..LeftPair::Public::LEN].copy_from_slice(left_pub.as_ref()); + raw[LeftPair::Public::LEN..].copy_from_slice(right_pub.as_ref()); + Self::Public::unchecked_from(raw) } fn sign(&self, message: &[u8]) -> Self::Signature { - let mut r: [u8; SIGNATURE_LEN] = [0u8; SIGNATURE_LEN]; - r[..Self::Signature::LEFT_SIGNATURE_LEN].copy_from_slice(self.left.sign(message).as_ref()); - r[Self::Signature::LEFT_SIGNATURE_LEN..].copy_from_slice(self.right.sign(message).as_ref()); - Self::Signature::unchecked_from(r) + let mut r: [u8; SIGNATURE_LEN] = [0u8; SIGNATURE_LEN]; + r[..Self::Signature::LEFT_SIGNATURE_LEN].copy_from_slice(self.left.sign(message).as_ref()); + r[Self::Signature::LEFT_SIGNATURE_LEN..].copy_from_slice(self.right.sign(message).as_ref()); + Self::Signature::unchecked_from(r) } - fn verify>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool { - let mut vec_message = vec![0u8; message.as_ref().len()]; - vec_message.clone_from_slice(message.as_ref()); + fn verify>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool { + let mut vec_message = vec![0u8; message.as_ref().len()]; + vec_message.clone_from_slice(message.as_ref()); - LeftPair::verify(&sig.left, message, &pubkey.left) && RightPair::verify(&sig.right, vec_message, &pubkey.right) + LeftPair::verify(&sig.left, message, &pubkey.left) + && RightPair::verify(&sig.right, vec_message, &pubkey.right) } /// Get the seed/secret key for each key and then concatenate them. @@ -496,7 +666,6 @@ Signature: SignaturePa } } - // Test set exercising the (ECDSA, BLS12-377) implementation #[cfg(test)] mod test { @@ -505,7 +674,6 @@ mod test { use ecdsa_n_bls377::{Pair, Signature}; use hex_literal::hex; - #[test] fn default_phrase_should_be_used() { assert_eq!( @@ -516,25 +684,30 @@ mod test { ); } - #[test] - fn seed_and_derive_should_work() { - let seed_for_right_and_left = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); - let pair = Pair::from_seed(&seed_for_right_and_left); - // we are using hash to field so this is not going to work - // assert_eq!(pair.seed(), seed); - let path = vec![DeriveJunction::Hard([0u8; 32])]; - let derived = pair.derive(path.into_iter(), None).ok().unwrap().0; - assert_eq!( - derived.to_raw_vec(), - [hex!("b8eefc4937200a8382d00050e050ced2d4ab72cc2ef1b061477afb51564fdd61"), hex!("3a0626d095148813cd1642d38254f1cfff7eb8cc1a2fc83b2a135377c3554c12")].concat() - ); - } - + #[test] + fn seed_and_derive_should_work() { + let seed_for_right_and_left = + hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); + let pair = Pair::from_seed(&seed_for_right_and_left); + // we are using hash to field so this is not going to work + // assert_eq!(pair.seed(), seed); + let path = vec![DeriveJunction::Hard([0u8; 32])]; + let derived = pair.derive(path.into_iter(), None).ok().unwrap().0; + assert_eq!( + derived.to_raw_vec(), + [ + hex!("b8eefc4937200a8382d00050e050ced2d4ab72cc2ef1b061477afb51564fdd61"), + hex!("3a0626d095148813cd1642d38254f1cfff7eb8cc1a2fc83b2a135377c3554c12") + ] + .concat() + ); + } - #[test] - fn test_vector_should_work() { - let seed_left_and_right = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); - let pair = Pair::from_seed(&([seed_left_and_right].concat()[..].try_into().unwrap())); + #[test] + fn test_vector_should_work() { + let seed_left_and_right = + hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); + let pair = Pair::from_seed(&([seed_left_and_right].concat()[..].try_into().unwrap())); let public = pair.public(); assert_eq!( public, @@ -543,19 +716,20 @@ mod test { ), ), ); - let message = b""; - let signature = hex!("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00d1e3013161991e142d8751017d4996209c2ff8a9ee160f373733eda3b4b785ba6edce9f45f87104bbe07aa6aa6eb2780aa705efb2c13d3b317d6409d159d23bdc7cdd5c2a832d1551cf49d811d49c901495e527dbd532e3a462335ce2686009104aba7bc11c5b22be78f3198d2727a0b"); - let signature = Signature::unchecked_from(signature); - assert!(pair.sign(&message[..]) == signature); - assert!(Pair::verify(&signature, &message[..], &public)); - } - - #[test] - fn test_vector_by_string_should_work() { - let pair = Pair::from_string("0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", - None, - ) - .unwrap(); + let message = b""; + let signature = hex!("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00d1e3013161991e142d8751017d4996209c2ff8a9ee160f373733eda3b4b785ba6edce9f45f87104bbe07aa6aa6eb2780aa705efb2c13d3b317d6409d159d23bdc7cdd5c2a832d1551cf49d811d49c901495e527dbd532e3a462335ce2686009104aba7bc11c5b22be78f3198d2727a0b"); + let signature = Signature::unchecked_from(signature); + assert!(pair.sign(&message[..]) == signature); + assert!(Pair::verify(&signature, &message[..], &public)); + } + + #[test] + fn test_vector_by_string_should_work() { + let pair = Pair::from_string( + "0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", + None, + ) + .unwrap(); let public = pair.public(); assert_eq!( public, @@ -564,99 +738,101 @@ mod test { ), ), ); - let message = b""; - let signature = hex!("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00bbb395bbdee1a35930912034f5fde3b36df2835a0536c865501b0675776a1d5931a3bea2e66eff73b2546c6af2061a8019223e4ebbbed661b2538e0f5823f2c708eb89c406beca8fcb53a5c13dbc7c0c42e4cf2be2942bba96ea29297915a06bd2b1b979c0e2ac8fd4ec684a6b5d110c"); - let signature = Signature::unchecked_from(signature); - assert!(pair.sign(&message[..]) == signature); - assert!(Pair::verify(&signature, &message[..], &public)); - } - - #[test] - fn generated_pair_should_work() { - let (pair, _) = Pair::generate(); - let public = pair.public(); - let message = b"Something important"; - let signature = pair.sign(&message[..]); - assert!(Pair::verify(&signature, &message[..], &public)); - assert!(!Pair::verify(&signature, b"Something else", &public)); - } - - - #[test] - fn seeded_pair_should_work() { - let pair = Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap())); - let public = pair.public(); - assert_eq!( + let message = b""; + let signature = hex!("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00bbb395bbdee1a35930912034f5fde3b36df2835a0536c865501b0675776a1d5931a3bea2e66eff73b2546c6af2061a8019223e4ebbbed661b2538e0f5823f2c708eb89c406beca8fcb53a5c13dbc7c0c42e4cf2be2942bba96ea29297915a06bd2b1b979c0e2ac8fd4ec684a6b5d110c"); + let signature = Signature::unchecked_from(signature); + assert!(pair.sign(&message[..]) == signature); + assert!(Pair::verify(&signature, &message[..], &public)); + } + + #[test] + fn generated_pair_should_work() { + let (pair, _) = Pair::generate(); + let public = pair.public(); + let message = b"Something important"; + let signature = pair.sign(&message[..]); + assert!(Pair::verify(&signature, &message[..], &public)); + assert!(!Pair::verify(&signature, b"Something else", &public)); + } + + #[test] + fn seeded_pair_should_work() { + let pair = + Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap())); + let public = pair.public(); + assert_eq!( public, Public::unchecked_from( hex!("035676109c54b9a16d271abeb4954316a40a32bcce023ac14c8e26e958aa68fba9754d2f2bbfa67df54d7e0e951979a18a1e0f45948857752cc2bac6bbb0b1d05e8e48bcc453920bf0c4bbd5993212480112a1fb433f04d74af0a8b700d93dc957ab3207f8d071e948f5aca1a7632c00bdf6d06be05b43e2e6216dccc8a5d55a0071cb2313cfd60b7e9114619cd17c06843b352f0b607a99122f6651df8f02e1ad3697bd208e62af047ddd7b942ba80080") ), ); - let message = + let message = hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000" ); - let signature = pair.sign(&message[..]); - println!("Correct signature: {:?}", signature); - assert!(Pair::verify(&signature, &message[..], &public)); - assert!(!Pair::verify(&signature, "Other message", &public)); - } - - #[test] - fn generate_with_phrase_recovery_possible() { - let (pair1, phrase, _) = Pair::generate_with_phrase(None); - let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap(); - - assert_eq!(pair1.public(), pair2.public()); - } - - #[test] - fn generate_with_password_phrase_recovery_possible() { - let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password")); - let (pair2, _) = Pair::from_phrase(&phrase, Some("password")).unwrap(); - - assert_eq!(pair1.public(), pair2.public()); - } - - #[test] - fn password_does_something() { - let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password")); - let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap(); - - assert_ne!(pair1.public(), pair2.public()); - } - - #[test] - fn ss58check_roundtrip_works() { - let pair = Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap())); - let public = pair.public(); - let s = public.to_ss58check(); - println!("Correct: {}", s); - let cmp = Public::from_ss58check(&s).unwrap(); - assert_eq!(cmp, public); - } - - #[test] - fn signature_serialization_works() { - let pair = Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap())); - let message = b"Something important"; - let signature = pair.sign(&message[..]); - - let serialized_signature = serde_json::to_string(&signature).unwrap(); - println!("{:?} -- {:}", signature.inner, serialized_signature); - // Signature is 177 bytes, hexify * 2, so 354 chars + 2 quote charsy - assert_eq!(serialized_signature.len(), 356); - let signature = serde_json::from_str(&serialized_signature).unwrap(); - assert!(Pair::verify(&signature, &message[..], &pair.public())); - } - - #[test] - fn signature_serialization_doesnt_panic() { - fn deserialize_signature(text: &str) -> Result { - serde_json::from_str(text) - } - assert!(deserialize_signature("Not valid json.").is_err()); - assert!(deserialize_signature("\"Not an actual signature.\"").is_err()); - // Poorly-sized - assert!(deserialize_signature("\"abc123\"").is_err()); - } + let signature = pair.sign(&message[..]); + println!("Correct signature: {:?}", signature); + assert!(Pair::verify(&signature, &message[..], &public)); + assert!(!Pair::verify(&signature, "Other message", &public)); + } + + #[test] + fn generate_with_phrase_recovery_possible() { + let (pair1, phrase, _) = Pair::generate_with_phrase(None); + let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap(); + + assert_eq!(pair1.public(), pair2.public()); + } + + #[test] + fn generate_with_password_phrase_recovery_possible() { + let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password")); + let (pair2, _) = Pair::from_phrase(&phrase, Some("password")).unwrap(); + + assert_eq!(pair1.public(), pair2.public()); + } + + #[test] + fn password_does_something() { + let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password")); + let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap(); + + assert_ne!(pair1.public(), pair2.public()); + } + + #[test] + fn ss58check_roundtrip_works() { + let pair = + Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap())); + let public = pair.public(); + let s = public.to_ss58check(); + println!("Correct: {}", s); + let cmp = Public::from_ss58check(&s).unwrap(); + assert_eq!(cmp, public); + } + + #[test] + fn signature_serialization_works() { + let pair = + Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap())); + let message = b"Something important"; + let signature = pair.sign(&message[..]); + + let serialized_signature = serde_json::to_string(&signature).unwrap(); + println!("{:?} -- {:}", signature.inner, serialized_signature); + // Signature is 177 bytes, hexify * 2, so 354 chars + 2 quote charsy + assert_eq!(serialized_signature.len(), 356); + let signature = serde_json::from_str(&serialized_signature).unwrap(); + assert!(Pair::verify(&signature, &message[..], &pair.public())); + } + + #[test] + fn signature_serialization_doesnt_panic() { + fn deserialize_signature(text: &str) -> Result { + serde_json::from_str(text) + } + assert!(deserialize_signature("Not valid json.").is_err()); + assert!(deserialize_signature("\"Not an actual signature.\"").is_err()); + // Poorly-sized + assert!(deserialize_signature("\"abc123\"").is_err()); + } }