From 5d3dce151440a6cd28fe068cf34c0780447581c1 Mon Sep 17 00:00:00 2001 From: Skalman <skalman@riseup.net> Date: Thu, 3 Aug 2023 14:52:16 +0200 Subject: [PATCH 01/30] First definition for pair public keys --- substrate/primitives/core/src/lib.rs | 1 + .../primitives/core/src/paired_crypto.rs | 81 +++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 substrate/primitives/core/src/paired_crypto.rs diff --git a/substrate/primitives/core/src/lib.rs b/substrate/primitives/core/src/lib.rs index 3a0e1f33f16c9..7174e8b34aad9 100644 --- a/substrate/primitives/core/src/lib.rs +++ b/substrate/primitives/core/src/lib.rs @@ -59,6 +59,7 @@ pub use paste; pub mod bandersnatch; #[cfg(feature = "bls-experimental")] pub mod bls; +pub mod paired_crypto; pub mod defer; pub mod ecdsa; pub mod ed25519; diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs new file mode 100644 index 0000000000000..e999860336e6b --- /dev/null +++ b/substrate/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<ecdsa:Pair, bls377:Pair>; + /// BLS12-377 public key. + pub type Public = super::Public<ecdsa::Public, ed25519::Public>; + // /// BLS12-377 signature. + //pub type Signature = super::Signature<ecdsa:Signature, bls377: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<LeftPublic: TraitPublic, RightPublic: TraitPublic> { + left_public : LeftPublic, + right_public: RightPublic, +} + +#[cfg(feature = "full_crypto")] +impl<T1: TraitPublic, T2: TraitPublicc> sp_std::hash::Hash for Public<T1,T2> { + fn hash<H: sp_std::hash::Hasher>(&self, state: &mut H) { + self.left_public.hash(state); + self.right_public.hash(state); + } +} + From be890d4bdbdad43cd95aeda5a5223d28ac5438e4 Mon Sep 17 00:00:00 2001 From: Skalman <skalman@riseup.net> Date: Thu, 3 Aug 2023 16:35:02 +0200 Subject: [PATCH 02/30] 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/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index e999860336e6b..0dbab1cd960f1 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/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<LeftPublic: TraitPublic, RightPublic: TraitPublic> { +pub struct PublicWithInner<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_SIZE: usize> { + inner: [u8; LEFT_PLUS_RIGHT_SIZE], + _phantom: PhantomData<fn() -> (LeftPublic, RightPublic)>, +} + +pub struct Public<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound> { left_public : LeftPublic, right_public: RightPublic, } -#[cfg(feature = "full_crypto")] -impl<T1: TraitPublic, T2: TraitPublicc> sp_std::hash::Hash for Public<T1,T2> { - fn hash<H: sp_std::hash::Hasher>(&self, state: &mut H) { - self.left_public.hash(state); - self.right_public.hash(state); - } -} +// #[cfg(feature = "full_crypto")] +// impl<T1: PublicKeyBound, T2: PublicKeyBound> sp_std::hash::Hash for Public<T1,T2> { +// fn hash<H: sp_std::hash::Hasher>(&self, state: &mut H) { +// self.left_public.hash(state); +// self.right_public.hash(state); +// } +// } + +// impl<T1: TraitPublic, T2: TraitPublic> ByteArray for Public<T1,T2> { +// const LEN: usize = T1::LEN + T2::LEN; +// } + +// impl<T1: PublicKeyBound, T2: PublicKeyBound> TryFrom<&[u8]> for Public<T1,T2> { +// type Error = (); + +// fn try_from(data: &[u8]) -> Result<Self, Self::Error> { +// // 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<T1,T2> AsMut<[u8]> for Public<T1,T2> { +// fn as_mut(&mut self) -> &mut [u8] { +// &mut self.inner[..] +// } +// } From fb6a0180a934fdbc5b350562f371732c146fe63d Mon Sep 17 00:00:00 2001 From: Skalman <skalman@riseup.net> Date: Mon, 14 Aug 2023 10:15:06 -0400 Subject: [PATCH 03/30] - 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/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 0dbab1cd960f1..59fb3bbf0aa36 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/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<ecdsa:Pair, bls377:Pair>; /// BLS12-377 public key. - pub type Public = super::Public<ecdsa::Public, ed25519::Public>; + pub type Public = super::Public<ecdsa::Public, ed25519::Public, 32, 32>; // /// BLS12-377 signature. //pub type Signature = super::Signature<ecdsa:Signature, bls377: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<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_SIZE: usize> { - inner: [u8; LEFT_PLUS_RIGHT_SIZE], - _phantom: PhantomData<fn() -> (LeftPublic, RightPublic)>, +pub struct Public<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_LEN: usize, const RIGHT_LEN: usize,> (LeftPublic, RightPublic); + +#[cfg(feature = "full_crypto")] +impl<LeftPublic: PublicKeyBound + UncheckedFrom<[u8; LEFT_LEN]>, RightPublic: PublicKeyBound + UncheckedFrom<[u8; RIGHT_LEN]>, const LEFT_LEN: usize, const RIGHT_LEN: usize> sp_std::hash::Hash for Public<LeftPublic, RightPublic, LEFT_LEN, RIGHT_LEN> { + fn hash<H: sp_std::hash::Hasher>(&self, state: &mut H) { + self.0.hash(state); + self.1.hash(state); + } } -pub struct Public<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound> { - left_public : LeftPublic, - right_public: RightPublic, +impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_LEN: usize, const RIGHT_LEN: usize> ByteArray for Public<LeftPublic, RightPublic, LEFT_LEN, RIGHT_LEN> where for<'a> Public<LeftPublic, RightPublic, LEFT_LEN, RIGHT_LEN>: TryFrom<&'a [u8], Error = ()> + AsRef<[u8]> + AsMut<[u8]> { + const LEN: usize = LeftPublic::LEN + RightPublic::LEN; } -// #[cfg(feature = "full_crypto")] -// impl<T1: PublicKeyBound, T2: PublicKeyBound> sp_std::hash::Hash for Public<T1,T2> { -// fn hash<H: sp_std::hash::Hasher>(&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<LeftPublic, RightPublic, LEFT_LEN, RIGHT_LEN> { + type Error = (); + + fn try_from(data: &[u8]) -> Result<Self, Self::Error> { + 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<T1: TraitPublic, T2: TraitPublic> ByteArray for Public<T1,T2> { -// const LEN: usize = T1::LEN + T2::LEN; +// impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_LEN: usize, const RIGHT_LEN: usize> AsMut<[u8]> for Public<LeftPublic, RightPublic, LEFT_LEN, RIGHT_LEN> { +// fn as_mut(&mut self) -> &mut [u8] { +// &mut [self.0.as_mut(), self.1.as_mut()].concat() +// } // } -// impl<T1: PublicKeyBound, T2: PublicKeyBound> TryFrom<&[u8]> for Public<T1,T2> { -// type Error = (); - -// fn try_from(data: &[u8]) -> Result<Self, Self::Error> { -// // 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<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_LEN: usize, const RIGHT_LEN: usize, const RIGHT_PLUS_LEFT_LEN: usize> AsRef<[u8; RIGHT_PLUS_LEFT_LEN]> for Public<LeftPublic, RightPublic, LEFT_LEN, RIGHT_LEN> where for<'a> Public<LeftPublic, RightPublic, LEFT_LEN, RIGHT_LEN>: 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<T1,T2> AsMut<[u8]> for Public<T1,T2> { -// fn as_mut(&mut self) -> &mut [u8] { -// &mut self.inner[..] -// } +// impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_LEN: usize, const RIGHT_LEN: usize,> AsRef<[u8]> for Public<LeftPublic, RightPublic, LEFT_LEN, RIGHT_LEN> { +// fn as_ref(&self) -> &[u8] { +// //let mut r : Vec<u8> = 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<u8> = [self.0.as_ref(), self.1.as_ref()].concat(); +// &r[..] +// } // } From 62ef8b14ce394d7919a26abd0877705b826d1012 Mon Sep 17 00:00:00 2001 From: Skalman <skalman@riseup.net> Date: Mon, 21 Aug 2023 09:12:50 -0400 Subject: [PATCH 04/30] 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/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 59fb3bbf0aa36..3ae113d9f3a4b 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/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<ecdsa:Pair, bls377:Pair>; /// BLS12-377 public key. - pub type Public = super::Public<ecdsa::Public, ed25519::Public, 32, 32>; + pub type Public = super::Public<ecdsa::Public, ed25519::Public, 64>; // /// BLS12-377 signature. //pub type Signature = super::Signature<ecdsa:Signature, bls377: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: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_LEN: usize, const RIGHT_LEN: usize,> (LeftPublic, RightPublic); +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 this instead of storing left and right but we are going to end up copying left and right. +// impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> { +// 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<LeftPublic: PublicKeyBound + UncheckedFrom<[u8; LEFT_LEN]>, RightPublic: PublicKeyBound + UncheckedFrom<[u8; RIGHT_LEN]>, const LEFT_LEN: usize, const RIGHT_LEN: usize> sp_std::hash::Hash for Public<LeftPublic, RightPublic, LEFT_LEN, RIGHT_LEN> { - fn hash<H: sp_std::hash::Hasher>(&self, state: &mut H) { - self.0.hash(state); - self.1.hash(state); +impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> sp_std::hash::Hash for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> { + fn hash<H: sp_std::hash::Hasher>(&self, state: &mut H) { + self.left.hash(state); + self.right.hash(state); } } -impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_LEN: usize, const RIGHT_LEN: usize> ByteArray for Public<LeftPublic, RightPublic, LEFT_LEN, RIGHT_LEN> where for<'a> Public<LeftPublic, RightPublic, LEFT_LEN, RIGHT_LEN>: TryFrom<&'a [u8], Error = ()> + AsRef<[u8]> + AsMut<[u8]> { - const LEN: usize = LeftPublic::LEN + RightPublic::LEN; +impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> ByteArray for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> { + 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<LeftPublic, RightPublic, LEFT_LEN, RIGHT_LEN> { - type Error = (); +impl<'a,LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> TryFrom<&'a[u8]> for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> { + type Error = (); + + fn try_from(data: &[u8]) -> Result<Self, Self::Error> { + 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<Self, Self::Error> { - 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<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> AsMut<[u8]> for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.inner[..] } } -// impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_LEN: usize, const RIGHT_LEN: usize> AsMut<[u8]> for Public<LeftPublic, RightPublic, LEFT_LEN, RIGHT_LEN> { -// fn as_mut(&mut self) -> &mut [u8] { -// &mut [self.0.as_mut(), self.1.as_mut()].concat() -// } -// } - -// impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_LEN: usize, const RIGHT_LEN: usize, const RIGHT_PLUS_LEFT_LEN: usize> AsRef<[u8; RIGHT_PLUS_LEFT_LEN]> for Public<LeftPublic, RightPublic, LEFT_LEN, RIGHT_LEN> where for<'a> Public<LeftPublic, RightPublic, LEFT_LEN, RIGHT_LEN>: 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<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> AsRef<[u8; LEFT_PLUS_RIGHT_LEN]> for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> { + fn as_ref(&self) -> &[u8; LEFT_PLUS_RIGHT_LEN] { + &self.inner + } +} -// impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_LEN: usize, const RIGHT_LEN: usize,> AsRef<[u8]> for Public<LeftPublic, RightPublic, LEFT_LEN, RIGHT_LEN> { -// fn as_ref(&self) -> &[u8] { -// //let mut r : Vec<u8> = 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<u8> = [self.0.as_ref(), self.1.as_ref()].concat(); -// &r[..] -// } -// } +impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize,> AsRef<[u8]> for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> { + fn as_ref(&self) -> &[u8] { + &self.inner[..] + } +} From 8d4e523787d05de385cf641e2da685d640faeb5c Mon Sep 17 00:00:00 2001 From: Skalman <skalman@riseup.net> Date: Mon, 21 Aug 2023 18:21:10 +0200 Subject: [PATCH 05/30] implement PassBy and From<Pair> for paired_crypto --- .../primitives/core/src/paired_crypto.rs | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 3ae113d9f3a4b..e2f1081c8393b 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/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<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RI &self.inner[..] } } + +impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize,> PassByInner for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> { + 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<LeftPair: TraitPair, RightPair: TraitPair, LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_PUBLIC_LEN: usize,> From<Pair<LeftPair, RightPair>> for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_PUBLIC_LEN> where Pair<LeftPair, RightPair> : TraitPair<Public = Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_PUBLIC_LEN>>, +{ + fn from(x: Pair<LeftPair, RightPair>) -> Self { + x.public() + } +} + +/// A key pair. +#[cfg(feature = "full_crypto")] +#[derive(Clone)] +pub struct Pair<LeftPair: TraitPair, RightPair: TraitPair>(LeftPair, RightPair); From eea74e27a40d3c74333676d2adeacd165772ae65 Mon Sep 17 00:00:00 2001 From: Skalman <skalman@riseup.net> Date: Tue, 22 Aug 2023 16:58:16 -0400 Subject: [PATCH 06/30] 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/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index e2f1081c8393b..5e384eb1155a2 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/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<ecdsa:Pair, bls377:Pair>; + pub type Pair = super::Pair<ecdsa::Pair, ed25519::Pair>; /// BLS12-377 public key. pub type Public = super::Public<ecdsa::Public, ed25519::Public, 64>; // /// BLS12-377 signature. //pub type Signature = super::Signature<ecdsa:Signature, bls377: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<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))] @@ -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<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RI #[cfg(feature = "full_crypto")] impl<LeftPair: TraitPair, RightPair: TraitPair, LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_PUBLIC_LEN: usize,> From<Pair<LeftPair, RightPair>> for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_PUBLIC_LEN> where Pair<LeftPair, RightPair> : TraitPair<Public = Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_PUBLIC_LEN>>, -{ + { fn from(x: Pair<LeftPair, RightPair>) -> Self { x.public() } } +impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize,> UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]> for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> { + 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<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize,> std::str::FromStr for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> where Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> : CryptoType { + type Err = crate::crypto::PublicError; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + <Self as Ss58Codec>::from_ss58check(s) + } +} + +#[cfg(feature = "std")] +impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize,> std::fmt::Display for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> where Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> : CryptoType { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", self.to_ss58check()) + } +} + +#[cfg(feature = "std")] +impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize,> sp_std::fmt::Debug for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> where Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> : 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<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize,>_sp_std::fmt::Debug for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> { + fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + + Ok(()) + } +} + +#[cfg(feature = "std")] +impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize,> Serialize for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> where Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> : CryptoType { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + 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<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> where Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> : CryptoType { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + Public::from_ss58check(&String::deserialize(deserializer)?) + .map_err(|e| de::Error::custom(format!("{:?}", e))) + + } +} + +impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize,> TraitPublic for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> where Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> : CryptoType {} + +impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize,> Derive for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> {} + +#[cfg(not(feature = "full_crypto"))] +impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_PUBLIC_LEN: usize,> CryptoType for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_PUBLIC_LEN> +{} + +//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<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_LEN: usize, const RIGHT_LEN: usize, const LEFT_PLUS_RIGHT_LEN: usize,> { + left: LeftSignature, + right: RightSignature, + inner: [u8; LEFT_PLUS_RIGHT_LEN], +} + +#[cfg(feature = "full_crypto")] +impl<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_LEN: usize, const RIGHT_LEN: usize, const LEFT_PLUS_RIGHT_LEN: usize> sp_std::hash::Hash for Signature<LeftSignature, RightSignature, LEFT_LEN, RIGHT_LEN, LEFT_PLUS_RIGHT_LEN> { + fn hash<H: sp_std::hash::Hasher>(&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<LeftSignature, RightSignature, LEFT_LEN, RIGHT_LEN, LEFT_PLUS_RIGHT_LEN> { + type Error = (); + + fn try_from(data: &[u8]) -> Result<Self, Self::Error> { + 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<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_LEN: usize, const RIGHT_LEN: usize, const LEFT_PLUS_RIGHT_LEN: usize> AsMut<[u8]> for Signature<LeftSignature, RightSignature, LEFT_LEN, RIGHT_LEN, LEFT_PLUS_RIGHT_LEN> { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.inner[..] + } +} + +impl<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_LEN: usize, const RIGHT_LEN: usize, const LEFT_PLUS_RIGHT_LEN: usize> AsRef<[u8; LEFT_PLUS_RIGHT_LEN]> for Signature<LeftSignature, RightSignature, LEFT_LEN, RIGHT_LEN, LEFT_PLUS_RIGHT_LEN> { + fn as_ref(&self) -> &[u8; LEFT_PLUS_RIGHT_LEN] { + &self.inner + } +} + +impl<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_LEN: usize, const RIGHT_LEN: usize, const LEFT_PLUS_RIGHT_LEN: usize,> AsRef<[u8]> for Signature<LeftSignature, RightSignature, LEFT_LEN, RIGHT_LEN, LEFT_PLUS_RIGHT_LEN> { + 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: TraitPair, RightPair: TraitPair>(LeftPair, RightPair); + + + From f407d87201373fb7e4dcc14a475b40be4dc51f01 Mon Sep 17 00:00:00 2001 From: Skalman <skalman@riseup.net> Date: Tue, 29 Aug 2023 05:00:05 -0400 Subject: [PATCH 07/30] 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/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 5e384eb1155a2..2f6838db86949 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/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<T: BlsBound> CryptoType for Signature<T> { +// #[cfg(feature = "full_crypto")] +// type Pair = Pair<T>; +// } + } /// 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<const LEFT_PLUS_RIGHT_LEN: usize> = [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<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RI let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; Public { left, right, inner } - } + } #[cfg(feature = "std")] @@ -205,7 +210,7 @@ impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RI } #[cfg(not(feature = "std"))] -impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize,>_sp_std::fmt::Debug for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> { +impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize,> sp_std::fmt::Debug for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> { 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<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_LEN: usize, const RIGHT_LEN: usize, const LEFT_PLUS_RIGHT_LEN: usize,> { +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; +} + #[cfg(feature = "full_crypto")] -impl<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_LEN: usize, const RIGHT_LEN: usize, const LEFT_PLUS_RIGHT_LEN: usize> sp_std::hash::Hash for Signature<LeftSignature, RightSignature, LEFT_LEN, RIGHT_LEN, LEFT_PLUS_RIGHT_LEN> { +impl<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize> sp_std::hash::Hash for Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN> { fn hash<H: sp_std::hash::Hasher>(&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<LeftSignature, RightSignature, LEFT_LEN, RIGHT_LEN, LEFT_PLUS_RIGHT_LEN> { +impl<'a,LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize> TryFrom<&'a[u8]> for Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN> where Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN>: SignaturePair { type Error = (); fn try_from(data: &[u8]) -> Result<Self, Self::Error> { 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<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_LEN: usize, const RIGHT_LEN: usize, const LEFT_PLUS_RIGHT_LEN: usize> AsMut<[u8]> for Signature<LeftSignature, RightSignature, LEFT_LEN, RIGHT_LEN, LEFT_PLUS_RIGHT_LEN> { +impl<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize> AsMut<[u8]> for Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN> { fn as_mut(&mut self) -> &mut [u8] { &mut self.inner[..] } } -impl<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_LEN: usize, const RIGHT_LEN: usize, const LEFT_PLUS_RIGHT_LEN: usize> AsRef<[u8; LEFT_PLUS_RIGHT_LEN]> for Signature<LeftSignature, RightSignature, LEFT_LEN, RIGHT_LEN, LEFT_PLUS_RIGHT_LEN> { +impl<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize> AsRef<[u8; LEFT_PLUS_RIGHT_LEN]> for Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN> { fn as_ref(&self) -> &[u8; LEFT_PLUS_RIGHT_LEN] { &self.inner } } -impl<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_LEN: usize, const RIGHT_LEN: usize, const LEFT_PLUS_RIGHT_LEN: usize,> AsRef<[u8]> for Signature<LeftSignature, RightSignature, LEFT_LEN, RIGHT_LEN, LEFT_PLUS_RIGHT_LEN> { +impl<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize,> AsRef<[u8]> for Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN> { fn as_ref(&self) -> &[u8] { &self.inner[..] } } - // serializer.serialize_str(&array_bytes::bytes2hex("", self)) +#[cfg(feature = "std")] +impl<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize,> Serialize for Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN> { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + 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<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN> { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + 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<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize,> From<Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN>> for [u8; LEFT_PLUS_RIGHT_LEN] +{ + fn from(signature: Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN>) -> [u8; LEFT_PLUS_RIGHT_LEN] { + signature.inner + } +} + +impl<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize,> sp_std::fmt::Debug for Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN> { + #[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<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize,> UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]> for Signature<LeftSignature, RightSignature,LEFT_PLUS_RIGHT_LEN> where Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN>: 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: TraitPair, RightPair: TraitPair>(LeftPair, RightPair); +pub struct Pair<LeftPair: TraitPair, RightPair: TraitPair,> { + 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<LeftPair: TraitPair, RightPair: TraitPair> Pair<LeftPair, RightPair> { +} + +#[cfg(feature = "full_crypto")] +impl<LeftPair: TraitPair, RightPair: TraitPair> TraitPair for Pair<LeftPair, RightPair> where + Pair<LeftPair, RightPair>: DoublePair + CryptoType, + LeftPair::Signature: SignatureBound, + RightPair::Signature: SignatureBound, +{ + type Seed = (LeftPair::Seed, RightPair::Seed); + type Public = Public<LeftPair::Public, RightPair::Public, {<Self as DoublePair>::PUBLIC_KEY_LEN}>; + type Signature = Signature<LeftPair::Signature, RightPair::Signature, { Self::SIGNATURE_LEN }>; + + fn from_seed_slice(seed_slice: &[u8]) -> Result<Self, SecretStringError> { + 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<Iter: Iterator<Item = DeriveJunction>>( + // &self, + // path: Iter, + // _seed: Option<Seed>, + // ) -> Result<(Self, Option<Seed>), 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::<T>(&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<M: AsRef<[u8]>>(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::<T>::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<u8> { + // self.0 + // .secret + // .to_bytes() + // .try_into() + // .expect("Secret key serializer returns a vector of SECRET_KEY_SERIALIZED_SIZE size") + // } +} From 2606cc4d12617a4123f029ad0653fcc144ac0a94 Mon Sep 17 00:00:00 2001 From: Skalman <skalman@riseup.net> Date: Thu, 31 Aug 2023 10:11:56 -0400 Subject: [PATCH 08/30] - 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/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 2f6838db86949..b76a7b42c0ff0 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/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<ecdsa::Pair, ed25519::Pair>; + pub type Pair = super::Pair<ecdsa::Pair, ed25519::Pair, 64, 64>; /// BLS12-377 public key. pub type Public = super::Public<ecdsa::Public, ed25519::Public, 64>; // /// 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<const LEFT_PLUS_RIGHT_LEN: usize> = [u8; {LEFT_PLUS_RIGHT_LEN}]; +pub trait SeedBound: Default + AsRef<[u8]> + AsMut<[u8]> + Clone {} +#[cfg(feature = "full_crypto")] +pub struct Seed<LeftSeed: SeedBound, RightSeed: SeedBound, const LEFT_PLUS_RIGHT_LEN: usize,> { + 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<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RI } #[cfg(feature = "full_crypto")] -impl<LeftPair: TraitPair, RightPair: TraitPair, LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_PUBLIC_LEN: usize,> From<Pair<LeftPair, RightPair>> for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_PUBLIC_LEN> where Pair<LeftPair, RightPair> : TraitPair<Public = Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_PUBLIC_LEN>>, +impl<LeftPair: TraitPair, RightPair: TraitPair, LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_PUBLIC_LEN: usize, const SIGNATURE_LEN: usize> From<Pair<LeftPair, RightPair, LEFT_PLUS_RIGHT_PUBLIC_LEN, SIGNATURE_LEN>> for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_PUBLIC_LEN> where Pair<LeftPair, RightPair, LEFT_PLUS_RIGHT_PUBLIC_LEN, SIGNATURE_LEN> : TraitPair<Public = Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_PUBLIC_LEN>>, { - fn from(x: Pair<LeftPair, RightPair>) -> Self { + fn from(x: Pair<LeftPair, RightPair, LEFT_PLUS_RIGHT_PUBLIC_LEN, SIGNATURE_LEN>) -> Self { x.public() } } @@ -179,8 +191,7 @@ impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RI 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 } + Public { left: left, right: right, inner: data } } } @@ -248,8 +259,9 @@ impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RI impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_PUBLIC_LEN: usize,> CryptoType for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_PUBLIC_LEN> {} + //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<LeftSignature, _> = data[0..Self::LEFT_SIGNATURE_LEN].try_into() else { panic!("invalid signature") }; + let Ok(mut right) : Result<RightSignature, _>= 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<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_P } #[cfg(feature = "std")] -impl<'de, LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize,> Deserialize<'de> for Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN> { +impl<'de,LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize,> Deserialize<'de> for Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN> where +Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN>: for<'a> TryFrom<&'a[u8]>{ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 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<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_P } } -impl<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize,> sp_std::fmt::Debug for Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN> { +impl<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize,> sp_std::fmt::Debug for Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN> 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<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_P impl<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize,> UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]> for Signature<LeftSignature, RightSignature,LEFT_PLUS_RIGHT_LEN> where Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN>: 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<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_ /// A key pair. #[cfg(feature = "full_crypto")] #[derive(Clone)] -pub struct Pair<LeftPair: TraitPair, RightPair: TraitPair,> { +pub struct Pair<LeftPair: TraitPair, RightPair: TraitPair, const PUBLIC_KEY_LEN: usize, const SIGNATURE_LEN: usize> +{ left: LeftPair, right: RightPair, @@ -383,64 +401,87 @@ trait HardJunctionId { } #[cfg(feature = "full_crypto")] -impl<LeftPair: TraitPair, RightPair: TraitPair> Pair<LeftPair, RightPair> { +impl<LeftPair: TraitPair, RightPair: TraitPair, const PUBLIC_KEY_LEN: usize, const SIGNATURE_LEN: usize> Pair<LeftPair, RightPair, PUBLIC_KEY_LEN, SIGNATURE_LEN> { } #[cfg(feature = "full_crypto")] -impl<LeftPair: TraitPair, RightPair: TraitPair> TraitPair for Pair<LeftPair, RightPair> where - Pair<LeftPair, RightPair>: DoublePair + CryptoType, +impl<LeftPair: TraitPair, RightPair: TraitPair, const PUBLIC_KEY_LEN: usize, const SIGNATURE_LEN: usize> TraitPair for Pair<LeftPair, RightPair, PUBLIC_KEY_LEN, SIGNATURE_LEN> where + Pair<LeftPair, RightPair, PUBLIC_KEY_LEN, SIGNATURE_LEN>: DoublePair + CryptoType, LeftPair::Signature: SignatureBound, RightPair::Signature: SignatureBound, +Public<LeftPair::Public, RightPair::Public, PUBLIC_KEY_LEN>: CryptoType, +Signature<LeftPair::Signature, RightPair::Signature, SIGNATURE_LEN>: SignaturePair, + LeftPair::Seed: SeedBound, + RightPair::Seed: SeedBound, +Seed<LeftPair::Seed, RightPair::Seed, DOUBLE_SEED_LEN>: SeedBound, { - type Seed = (LeftPair::Seed, RightPair::Seed); - type Public = Public<LeftPair::Public, RightPair::Public, {<Self as DoublePair>::PUBLIC_KEY_LEN}>; - type Signature = Signature<LeftPair::Signature, RightPair::Signature, { Self::SIGNATURE_LEN }>; + type Seed = Seed<LeftPair::Seed, RightPair::Seed, DOUBLE_SEED_LEN>; + type Public = Public<LeftPair::Public, RightPair::Public, PUBLIC_KEY_LEN>; + type Signature = Signature<LeftPair::Signature, RightPair::Signature, SIGNATURE_LEN>; fn from_seed_slice(seed_slice: &[u8]) -> Result<Self, SecretStringError> { 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<Iter: Iterator<Item = DeriveJunction>>( - // &self, - // path: Iter, - // _seed: Option<Seed>, - // ) -> Result<(Self, Option<Seed>), 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::<T>(&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<Iter: Iterator<Item = DeriveJunction>>( + &self, + path: Iter, + seed: Option<Self::Seed>, + ) -> Result<(Self, Option<Self::Seed>), 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<M: AsRef<[u8]>>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool { + fn verify<M: AsRef<[u8]>>(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<LeftPair: TraitPair, RightPair: TraitPair> TraitPair for Pair<LeftPair, Rig // Err(_) => 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<u8> { - // 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<u8> { + [self.left.to_raw_vec(), self.left.to_raw_vec()].concat() + } } From 00933da3589c5d6527e40b6b1e6fcf103824bae2 Mon Sep 17 00:00:00 2001 From: Skalman <skalman@riseup.net> Date: Tue, 5 Sep 2023 16:58:31 -0400 Subject: [PATCH 09/30] implement sgin and verify for --- .../primitives/core/src/paired_crypto.rs | 36 +++++-------------- 1 file changed, 9 insertions(+), 27 deletions(-) diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index b76a7b42c0ff0..6f9abbc18c394 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -473,36 +473,17 @@ Seed<LeftPair::Seed, RightPair::Seed, DOUBLE_SEED_LEN>: 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<M: AsRef<[u8]>>(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::<T>::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<M: AsRef<[u8]>>(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<LeftPair::Seed, RightPair::Seed, DOUBLE_SEED_LEN>: SeedBound, [self.left.to_raw_vec(), self.left.to_raw_vec()].concat() } } + From e7719ab3aa1b14ce5fa34b3161f69e403a482c62 Mon Sep 17 00:00:00 2001 From: Skalman <skalman@riseup.net> Date: Sun, 10 Sep 2023 14:02:12 -0400 Subject: [PATCH 10/30] Actually implementing `paired_crypto::{Pair, Public, Signatrue}` for paired (ECDSA, BLS377) crypto --- substrate/primitives/core/src/bls.rs | 4 +- .../primitives/core/src/paired_crypto.rs | 104 ++++++++++++++---- 2 files changed, 83 insertions(+), 25 deletions(-) diff --git a/substrate/primitives/core/src/bls.rs b/substrate/primitives/core/src/bls.rs index 951aa1828ea51..40fc29ffa5443 100644 --- a/substrate/primitives/core/src/bls.rs +++ b/substrate/primitives/core/src/bls.rs @@ -89,11 +89,11 @@ const SECRET_KEY_SERIALIZED_SIZE: usize = <SecretKey<TinyBLS381> as SerializableToBytes>::SERIALIZED_BYTES_SIZE; // Public key serialized size -const PUBLIC_KEY_SERIALIZED_SIZE: usize = +pub const PUBLIC_KEY_SERIALIZED_SIZE: usize = <DoublePublicKey<TinyBLS381> as SerializableToBytes>::SERIALIZED_BYTES_SIZE; // Signature serialized size -const SIGNATURE_SERIALIZED_SIZE: usize = +pub const SIGNATURE_SERIALIZED_SIZE: usize = <DoubleSignature<TinyBLS381> as SerializableToBytes>::SERIALIZED_BYTES_SIZE; /// A secret seed. diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 6f9abbc18c394..a43f030fdc0f0 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/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<ecdsa::Pair, ed25519::Pair, 64, 64>; + /// 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<ecdsa::Pair, bls377::Pair, PUBLIC_KEY_LEN, SIGNATURE_LEN>; /// BLS12-377 public key. - pub type Public = super::Public<ecdsa::Public, ed25519::Public, 64>; + pub type Public = super::Public<ecdsa::Public, bls377::Public, PUBLIC_KEY_LEN>; // /// BLS12-377 signature. - //pub type Signature = super::Signature<ecdsa:Signature, bls377:Signature>; - - // impl super::CryptoType for Public - // { - // #[cfg(feature = "full_crypto")] - // type Pair = Pair; - // } - // impl super::HardJunctionId for TinyBLS377 { - // const ID: &'static str = "BLS12377HDKD"; - // } - -// impl<T: BlsBound> CryptoType for Signature<T> { -// #[cfg(feature = "full_crypto")] -// type Pair = Pair<T>; -// } + pub type Signature = super::Signature<ecdsa::Signature, bls377::Signature,SIGNATURE_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; + } + + #[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<SeedTrait: Default + AsRef<[u8]> + AsMut<[u8]> + Clone> SeedBound for SeedTrait {} + #[cfg(feature = "full_crypto")] +#[derive(Clone)] pub struct Seed<LeftSeed: SeedBound, RightSeed: SeedBound, const LEFT_PLUS_RIGHT_LEN: usize,> { left: LeftSeed, right: RightSeed, inner: [u8; LEFT_PLUS_RIGHT_LEN], } + +#[cfg(feature = "full_crypto")] +impl<LeftSeed: SeedBound, RightSeed: SeedBound, const LEFT_PLUS_RIGHT_LEN: usize,> Default for Seed<LeftSeed, RightSeed, LEFT_PLUS_RIGHT_LEN> { + 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<LeftSeed: SeedBound, RightSeed: SeedBound, const LEFT_PLUS_RIGHT_LEN: usize,> AsRef<[u8]> for Seed<LeftSeed, RightSeed, LEFT_PLUS_RIGHT_LEN> { + fn as_ref(&self) -> &[u8] { + &self.inner[..] + } +} + +#[cfg(feature = "full_crypto")] +impl<LeftSeed: SeedBound, RightSeed: SeedBound, const LEFT_PLUS_RIGHT_LEN: usize> AsMut<[u8]> for Seed<LeftSeed, RightSeed, LEFT_PLUS_RIGHT_LEN> { + 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<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RI //pub trait Public: ByteArray + Derive + CryptoType + PartialEq + Eq + Clone + Send + Sync {} pub trait SignatureBound: sp_std::hash::Hash + for<'a> TryFrom<&'a[u8]> + AsRef<[u8]> {} +impl<SignatureTrait: sp_std::hash::Hash + for<'a> 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<LeftPair::Seed, RightPair::Seed, DOUBLE_SEED_LEN>: SeedBound, } } + From 7a9b67777977248e49306a07b6235e69da598f49 Mon Sep 17 00:00:00 2001 From: Skalman <skalman@riseup.net> Date: Mon, 11 Sep 2023 05:58:28 -0400 Subject: [PATCH 11/30] Implement and pass all test for `paired_crypto` --- substrate/primitives/core/src/crypto.rs | 2 +- substrate/primitives/core/src/hexdisplay.rs | 2 +- .../primitives/core/src/paired_crypto.rs | 242 ++++++++++++++++-- 3 files changed, 216 insertions(+), 30 deletions(-) diff --git a/substrate/primitives/core/src/crypto.rs b/substrate/primitives/core/src/crypto.rs index 8c7d98f00cd89..946ebfaeb836d 100644 --- a/substrate/primitives/core/src/crypto.rs +++ b/substrate/primitives/core/src/crypto.rs @@ -1197,7 +1197,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/substrate/primitives/core/src/hexdisplay.rs b/substrate/primitives/core/src/hexdisplay.rs index 30e045dfc52ac..72bb24a186e54 100644 --- a/substrate/primitives/core/src/hexdisplay.rs +++ b/substrate/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/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index a43f030fdc0f0..81d41a52394c4 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/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<ecdsa::Signature, bls377::Signature,SIGNATURE_LEN>; + 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<Self, Self::Error> { + 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<LeftSeed: SeedBound, RightSeed: SeedBound, const LEFT_PLUS_RIGHT_LEN: usize } + + //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 {} @@ -184,13 +205,14 @@ impl<'a,LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS type Error = (); fn try_from(data: &[u8]) -> Result<Self, Self::Error> { - 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<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RI } fn from_inner(inner: Self::Inner) -> 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<RightSignature, _>= 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<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_ 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 } + Signature { left, right, inner: data } } } @@ -477,12 +498,12 @@ Seed<LeftPair::Seed, RightPair::Seed, DOUBLE_SEED_LEN>: SeedBound, type Signature = Signature<LeftPair::Signature, RightPair::Signature, SIGNATURE_LEN>; fn from_seed_slice(seed_slice: &[u8]) -> Result<Self, SecretStringError> { - 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<Iter: Iterator<Item = DeriveJunction>>( @@ -493,20 +514,19 @@ Seed<LeftPair::Seed, RightPair::Seed, DOUBLE_SEED_LEN>: 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<LeftPair::Seed, RightPair::Seed, DOUBLE_SEED_LEN>: 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<LeftPair::Seed, RightPair::Seed, DOUBLE_SEED_LEN>: 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<LeftPair::Seed, RightPair::Seed, DOUBLE_SEED_LEN>: SeedBound, /// Get the seed for this key. fn to_raw_vec(&self) -> Vec<u8> { - [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<Signature, serde_json::error::Error> { + 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 a01a814d6764a89a55c2ef7619f25e63f3b35c18 Mon Sep 17 00:00:00 2001 From: Skalman <skalman@riseup.net> Date: Mon, 25 Sep 2023 15:53:15 -0400 Subject: [PATCH 12/30] - 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`. - cargo fmt pair_crypto.rs --- substrate/primitives/core/src/bls.rs | 19 +- .../primitives/core/src/paired_crypto.rs | 828 ++++++++++-------- 2 files changed, 473 insertions(+), 374 deletions(-) diff --git a/substrate/primitives/core/src/bls.rs b/substrate/primitives/core/src/bls.rs index 40fc29ffa5443..8e9f8ec356a98 100644 --- a/substrate/primitives/core/src/bls.rs +++ b/substrate/primitives/core/src/bls.rs @@ -83,16 +83,16 @@ trait BlsBound: EngineBLS + HardJunctionId + Send + Sync + 'static {} impl<T: EngineBLS + HardJunctionId + Send + Sync + 'static> BlsBound for T {} -// Secret key serialized size +/// Secret key serialized size #[cfg(feature = "full_crypto")] const SECRET_KEY_SERIALIZED_SIZE: usize = <SecretKey<TinyBLS381> as SerializableToBytes>::SERIALIZED_BYTES_SIZE; -// Public key serialized size +/// Public key serialized size pub const PUBLIC_KEY_SERIALIZED_SIZE: usize = <DoublePublicKey<TinyBLS381> as SerializableToBytes>::SERIALIZED_BYTES_SIZE; -// Signature serialized size +/// Signature serialized size pub const SIGNATURE_SERIALIZED_SIZE: usize = <DoubleSignature<TinyBLS381> as SerializableToBytes>::SERIALIZED_BYTES_SIZE; @@ -258,7 +258,7 @@ impl<T> sp_std::fmt::Debug for Public<T> { } } -#[cfg(feature = "std")] +#[cfg(feature = "serde")] impl<T: BlsBound> Serialize for Public<T> { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where @@ -268,7 +268,7 @@ impl<T: BlsBound> Serialize for Public<T> { } } -#[cfg(feature = "std")] +#[cfg(feature = "serde")] impl<'de, T: BlsBound> Deserialize<'de> for Public<T> { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where @@ -330,7 +330,7 @@ impl<T> TryFrom<&[u8]> for Signature<T> { } } -#[cfg(feature = "std")] +#[cfg(feature = "serde")] impl<T> Serialize for Signature<T> { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where @@ -340,7 +340,7 @@ impl<T> Serialize for Signature<T> { } } -#[cfg(feature = "std")] +#[cfg(feature = "serde")] impl<'de, T> Deserialize<'de> for Signature<T> { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where @@ -529,11 +529,10 @@ mod test { ); } - // Only passes if the seed = (seed mod ScalarField) #[test] fn seed_and_derive_should_work() { let seed = array_bytes::hex2array_unchecked( - "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f00", + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", ); let pair = Pair::from_seed(&seed); // we are using hash to field so this is not going to work @@ -543,7 +542,7 @@ mod test { assert_eq!( derived.to_raw_vec(), array_bytes::hex2array_unchecked::<_, 32>( - "a4f2269333b3e87c577aa00c4a2cd650b3b30b2e8c286a47c251279ff3a26e0d" + "3a0626d095148813cd1642d38254f1cfff7eb8cc1a2fc83b2a135377c3554c12" ) ); } diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 81d41a52394c4..968930b73d511 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/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,151 +32,110 @@ 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}; - - /// 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; - const LEFT_SEED_LEN: usize = SECURE_SEED_LEN; - const RIGHT_SEED_LEN: usize = SECURE_SEED_LEN; - - /// BLS12-377 key pair. - #[cfg(feature = "full_crypto")] - pub type Pair = super::Pair<ecdsa::Pair, bls377::Pair, PUBLIC_KEY_LEN, SIGNATURE_LEN>; - /// BLS12-377 public key. - pub type Public = super::Public<ecdsa::Public, bls377::Public, PUBLIC_KEY_LEN>; - // /// BLS12-377 signature. - pub type Signature = super::Signature<ecdsa::Signature, bls377::Signature,SIGNATURE_LEN>; - - 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; - } - - #[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; - } - - impl<'a> TryFrom<&'a[u8]> for Seed { - type Error = (); - - fn try_from(data: &[u8]) -> Result<Self, Self::Error> { - 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 }) - - } - } + 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"); -#[cfg(feature = "full_crypto")] -const SECURE_SEED_LEN: usize = 32; + 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; -#[cfg(feature = "full_crypto")] -const DOUBLE_SEED_LEN: usize = SECURE_SEED_LEN * 2; + /// (ECDSA, BLS12-377) key-pair pair. + #[cfg(feature = "full_crypto")] + pub type Pair = super::Pair<ecdsa::Pair, bls377::Pair, PUBLIC_KEY_LEN, SIGNATURE_LEN>; + /// (ECDSA, BLS12-377) public key pair. + pub type Public = super::Public<ecdsa::Public, bls377::Public, PUBLIC_KEY_LEN>; + /// (ECDSA, BLS12-377) signature pair. + pub type Signature = super::Signature<ecdsa::Signature, bls377::Signature, SIGNATURE_LEN>; -/// 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 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; + } -impl<SeedTrait: Default + AsRef<[u8]> + AsMut<[u8]> + Clone> SeedBound for SeedTrait {} + #[cfg(feature = "full_crypto")] + impl super::DoublePair for Pair { + const PUBLIC_KEY_LEN: usize = PUBLIC_KEY_LEN; + const SIGNATURE_LEN: usize = SIGNATURE_LEN; + } -#[cfg(feature = "full_crypto")] -#[derive(Clone)] -pub struct Seed<LeftSeed: SeedBound, RightSeed: SeedBound, const LEFT_PLUS_RIGHT_LEN: usize,> { - left: LeftSeed, - right: RightSeed, - inner: [u8; LEFT_PLUS_RIGHT_LEN], -} + impl super::CryptoType for Public { + #[cfg(feature = "full_crypto")] + type Pair = Pair; + } -#[cfg(feature = "full_crypto")] -impl<LeftSeed: SeedBound, RightSeed: SeedBound, const LEFT_PLUS_RIGHT_LEN: usize,> Default for Seed<LeftSeed, RightSeed, LEFT_PLUS_RIGHT_LEN> { - fn default() -> Self{ - Self { - left: LeftSeed::default(), right: RightSeed::default(), inner: [LeftSeed::default().as_ref(), RightSeed::default().as_ref()].concat().try_into().unwrap() + 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. #[cfg(feature = "full_crypto")] -impl<LeftSeed: SeedBound, RightSeed: SeedBound, const LEFT_PLUS_RIGHT_LEN: usize,> AsRef<[u8]> for Seed<LeftSeed, RightSeed, LEFT_PLUS_RIGHT_LEN> { - fn as_ref(&self) -> &[u8] { - &self.inner[..] - } -} +const SECURE_SEED_LEN: usize = 32; +/// 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")] -impl<LeftSeed: SeedBound, RightSeed: SeedBound, const LEFT_PLUS_RIGHT_LEN: usize> AsMut<[u8]> for Seed<LeftSeed, RightSeed, LEFT_PLUS_RIGHT_LEN> { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.inner[..] - } +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 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 {} - -impl<PublicKeyTrait: TraitPublic + Sized + Derive + sp_std::hash::Hash + ByteArray + for<'a> 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<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize,> { - 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 this instead of storing left and right but we are going to end up copying left and right. +// 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. // impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> { // inline fn left<'a>(&self)-> &'a LeftPublic { // &LeftPublic::try_from(&self.inner[0..LeftPublic::LEN]).unwrap() @@ -186,57 +145,69 @@ pub struct Public<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const // &RightPublic::try_from(&self.inner[LeftPublic::LEN..LEFT_PLUS_RIGHT_LEN]).unwrap() // } - // } #[cfg(feature = "full_crypto")] -impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> sp_std::hash::Hash for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> { - fn hash<H: sp_std::hash::Hasher>(&self, state: &mut H) { - self.left.hash(state); - self.right.hash(state); +impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> + sp_std::hash::Hash for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> +{ + fn hash<H: sp_std::hash::Hasher>(&self, state: &mut H) { + self.left.hash(state); + self.right.hash(state); } } -impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> ByteArray for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> { - const LEN: usize = LEFT_PLUS_RIGHT_LEN; +impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> + ByteArray for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> +{ + const LEN: usize = LEFT_PLUS_RIGHT_LEN; } -impl<'a,LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> TryFrom<&'a[u8]> for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> { - type Error = (); - - fn try_from(data: &[u8]) -> Result<Self, Self::Error> { - 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()?; +impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> + TryFrom<&[u8]> for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> +{ + type Error = (); - let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; - inner.copy_from_slice(data); - Ok(Public { left, right, inner }) + fn try_from(data: &[u8]) -> Result<Self, Self::Error> { + 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<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> AsMut<[u8]> for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.inner[..] - } + +impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> + AsMut<[u8]> for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> +{ + fn as_mut(&mut self) -> &mut [u8] { + &mut self.inner[..] + } } -impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> AsRef<[u8; LEFT_PLUS_RIGHT_LEN]> for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> { - fn as_ref(&self) -> &[u8; LEFT_PLUS_RIGHT_LEN] { +impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> + AsRef<[u8; LEFT_PLUS_RIGHT_LEN]> for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> +{ + fn as_ref(&self) -> &[u8; LEFT_PLUS_RIGHT_LEN] { &self.inner - } + } } -impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize,> AsRef<[u8]> for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> { - fn as_ref(&self) -> &[u8] { - &self.inner[..] - } +impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> + AsRef<[u8]> for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> +{ + fn as_ref(&self) -> &[u8] { + &self.inner[..] + } } -impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize,> PassByInner for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> { +impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> + PassByInner for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> +{ type Inner = [u8; LEFT_PLUS_RIGHT_LEN]; fn into_inner(self) -> Self::Inner { @@ -248,33 +219,49 @@ impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RI } 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(); + 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<LeftPair: TraitPair, RightPair: TraitPair, LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_PUBLIC_LEN: usize, const SIGNATURE_LEN: usize> From<Pair<LeftPair, RightPair, LEFT_PLUS_RIGHT_PUBLIC_LEN, SIGNATURE_LEN>> for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_PUBLIC_LEN> where Pair<LeftPair, RightPair, LEFT_PLUS_RIGHT_PUBLIC_LEN, SIGNATURE_LEN> : TraitPair<Public = Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_PUBLIC_LEN>>, - { +impl< + LeftPair: TraitPair, + RightPair: TraitPair, + LeftPublic: PublicKeyBound, + RightPublic: PublicKeyBound, + const LEFT_PLUS_RIGHT_PUBLIC_LEN: usize, + const SIGNATURE_LEN: usize, + > From<Pair<LeftPair, RightPair, LEFT_PLUS_RIGHT_PUBLIC_LEN, SIGNATURE_LEN>> + for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_PUBLIC_LEN> +where + Pair<LeftPair, RightPair, LEFT_PLUS_RIGHT_PUBLIC_LEN, SIGNATURE_LEN>: + TraitPair<Public = Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_PUBLIC_LEN>>, +{ fn from(x: Pair<LeftPair, RightPair, LEFT_PLUS_RIGHT_PUBLIC_LEN, SIGNATURE_LEN>) -> Self { x.public() } } -impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize,> UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]> for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> { +impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> + UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]> for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> +{ 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 } + Public { left, right, inner: data } } - } #[cfg(feature = "std")] -impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize,> std::str::FromStr for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> where Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> : CryptoType { +impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> + std::str::FromStr for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> +where + Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN>: CryptoType, +{ type Err = crate::crypto::PublicError; fn from_str(s: &str) -> Result<Self, Self::Err> { @@ -283,14 +270,23 @@ impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RI } #[cfg(feature = "std")] -impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize,> std::fmt::Display for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> where Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> : CryptoType { +impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> + std::fmt::Display for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> +where + Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN>: CryptoType, +{ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", self.to_ss58check()) } } #[cfg(feature = "std")] -impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize,> sp_std::fmt::Debug for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> where Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> : CryptoType, [u8;LEFT_PLUS_RIGHT_LEN]: crate::hexdisplay::AsBytesRef { +impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> + sp_std::fmt::Debug for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> +where + Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN>: 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]) @@ -298,111 +294,173 @@ impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RI } #[cfg(not(feature = "std"))] -impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize,> sp_std::fmt::Debug for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> { +impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> + sp_std::fmt::Debug for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> +{ fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - - Ok(()) + Ok(()) } } #[cfg(feature = "std")] -impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize,> Serialize for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> where Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> : CryptoType { +impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> + Serialize for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> +where + Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN>: CryptoType, +{ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 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<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> where Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> : CryptoType { +impl< + 'de, + LeftPublic: PublicKeyBound, + RightPublic: PublicKeyBound, + const LEFT_PLUS_RIGHT_LEN: usize, + > Deserialize<'de> for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> +where + Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN>: CryptoType, +{ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 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<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize,> TraitPublic for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> where Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> : CryptoType {} +impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> + TraitPublic for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> +where + Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN>: CryptoType, +{ +} -impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize,> Derive for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> {} +impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> + Derive for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> +{ +} #[cfg(not(feature = "full_crypto"))] -impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_PUBLIC_LEN: usize,> CryptoType for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_PUBLIC_LEN> -{} - +impl< + LeftPublic: PublicKeyBound, + RightPublic: PublicKeyBound, + const LEFT_PLUS_RIGHT_PUBLIC_LEN: usize, + > CryptoType for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_PUBLIC_LEN> +{ +} -//pub trait Public: ByteArray + Derive + CryptoType + PartialEq + Eq + Clone + Send + Sync {} -pub trait SignatureBound: sp_std::hash::Hash + for<'a> TryFrom<&'a[u8]> + AsRef<[u8]> {} +/// 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]> {} -impl<SignatureTrait: sp_std::hash::Hash + for<'a> TryFrom<&'a[u8]> + AsRef<[u8]>> SignatureBound for SignatureTrait {} +impl<SignatureTrait: sp_std::hash::Hash + for<'a> 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<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize,> { - 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<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize> sp_std::hash::Hash for Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN> { - fn hash<H: sp_std::hash::Hasher>(&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<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN> +{ + fn hash<H: sp_std::hash::Hasher>(&self, state: &mut H) { + self.left.hash(state); + self.right.hash(state); } } -impl<'a,LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize> TryFrom<&'a[u8]> for Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN> where Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN>: SignaturePair { - type Error = (); - - fn try_from(data: &[u8]) -> Result<Self, Self::Error> { - if data.len() != LEFT_PLUS_RIGHT_LEN { - return Err(()) - } - let Ok(mut left) : Result<LeftSignature, _> = data[0..Self::LEFT_SIGNATURE_LEN].try_into() else { panic!("invalid signature") }; - let Ok(mut right) : Result<RightSignature, _>= 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<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN> +where + Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN>: 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<Self, Self::Error> { + if data.len() != LEFT_PLUS_RIGHT_LEN { + return Err(()); + } + let Ok(left) : Result<LeftSignature, _> = data[0..Self::LEFT_SIGNATURE_LEN].try_into() else { panic!("invalid signature") }; + let Ok(right) : Result<RightSignature, _>= 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<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize> AsMut<[u8]> for Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN> { - 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<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN> +{ + fn as_mut(&mut self) -> &mut [u8] { + &mut self.inner[..] + } } -impl<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize> AsRef<[u8; LEFT_PLUS_RIGHT_LEN]> for Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN> { - 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<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN> +{ + fn as_ref(&self) -> &[u8; LEFT_PLUS_RIGHT_LEN] { &self.inner - } + } } -impl<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize,> AsRef<[u8]> for Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN> { - fn as_ref(&self) -> &[u8] { - &self.inner[..] - } +impl< + LeftSignature: SignatureBound, + RightSignature: SignatureBound, + const LEFT_PLUS_RIGHT_LEN: usize, + > AsRef<[u8]> for Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN> +{ + fn as_ref(&self) -> &[u8] { + &self.inner[..] + } } #[cfg(feature = "std")] -impl<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize,> Serialize for Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN> { +impl< + LeftSignature: SignatureBound, + RightSignature: SignatureBound, + const LEFT_PLUS_RIGHT_LEN: usize, + > Serialize for Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN> +{ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, @@ -411,29 +469,56 @@ impl<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_P } } -#[cfg(feature = "std")] -impl<'de,LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize,> Deserialize<'de> for Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN> where -Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN>: for<'a> TryFrom<&'a[u8]>{ +#[cfg(feature = "serde")] +impl< + 'de, + LeftSignature: SignatureBound, + RightSignature: SignatureBound, + const LEFT_PLUS_RIGHT_LEN: usize, + > Deserialize<'de> for Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN> +where + Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN>: SignaturePair, +{ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 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::<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN>::try_from( + signature_hex.as_ref(), + ) + .map_err(|e| { + de::Error::custom(format!( + "Error in converting deserialized data into signature: {:?}", + e + )) + }) } } -impl<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize,> From<Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN>> for [u8; LEFT_PLUS_RIGHT_LEN] +impl< + LeftSignature: SignatureBound, + RightSignature: SignatureBound, + const LEFT_PLUS_RIGHT_LEN: usize, + > From<Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN>> + for [u8; LEFT_PLUS_RIGHT_LEN] { - fn from(signature: Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN>) -> [u8; LEFT_PLUS_RIGHT_LEN] { + fn from( + signature: Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN>, + ) -> [u8; LEFT_PLUS_RIGHT_LEN] { signature.inner } } -impl<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize,> sp_std::fmt::Debug for Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN> 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<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN> +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)) @@ -445,141 +530,150 @@ impl<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_P } } -impl<LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize,> UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]> for Signature<LeftSignature, RightSignature,LEFT_PLUS_RIGHT_LEN> where Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN>: SignaturePair { +impl< + LeftSignature: SignatureBound, + RightSignature: SignatureBound, + const LEFT_PLUS_RIGHT_LEN: usize, + > UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]> + for Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN> +where + Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN>: 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 } + Signature { left, right, inner: data } } } /// A key pair. #[cfg(feature = "full_crypto")] #[derive(Clone)] -pub struct Pair<LeftPair: TraitPair, RightPair: TraitPair, const PUBLIC_KEY_LEN: usize, const SIGNATURE_LEN: usize> -{ - 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 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; + const PUBLIC_KEY_LEN: usize; + const SIGNATURE_LEN: usize; } #[cfg(feature = "full_crypto")] -impl<LeftPair: TraitPair, RightPair: TraitPair, const PUBLIC_KEY_LEN: usize, const SIGNATURE_LEN: usize> Pair<LeftPair, RightPair, PUBLIC_KEY_LEN, SIGNATURE_LEN> { +impl< + LeftPair: TraitPair, + RightPair: TraitPair, + const PUBLIC_KEY_LEN: usize, + const SIGNATURE_LEN: usize, + > Pair<LeftPair, RightPair, PUBLIC_KEY_LEN, SIGNATURE_LEN> +{ } #[cfg(feature = "full_crypto")] -impl<LeftPair: TraitPair, RightPair: TraitPair, const PUBLIC_KEY_LEN: usize, const SIGNATURE_LEN: usize> TraitPair for Pair<LeftPair, RightPair, PUBLIC_KEY_LEN, SIGNATURE_LEN> where - Pair<LeftPair, RightPair, PUBLIC_KEY_LEN, SIGNATURE_LEN>: DoublePair + CryptoType, - LeftPair::Signature: SignatureBound, - RightPair::Signature: SignatureBound, -Public<LeftPair::Public, RightPair::Public, PUBLIC_KEY_LEN>: CryptoType, -Signature<LeftPair::Signature, RightPair::Signature, SIGNATURE_LEN>: SignaturePair, - LeftPair::Seed: SeedBound, - RightPair::Seed: SeedBound, -Seed<LeftPair::Seed, RightPair::Seed, DOUBLE_SEED_LEN>: SeedBound, -{ - type Seed = Seed<LeftPair::Seed, RightPair::Seed, DOUBLE_SEED_LEN>; +impl< + LeftPair: TraitPair, + RightPair: TraitPair, + const PUBLIC_KEY_LEN: usize, + const SIGNATURE_LEN: usize, + > TraitPair for Pair<LeftPair, RightPair, PUBLIC_KEY_LEN, SIGNATURE_LEN> +where + Pair<LeftPair, RightPair, PUBLIC_KEY_LEN, SIGNATURE_LEN>: DoublePair + CryptoType, + LeftPair::Signature: SignatureBound, + RightPair::Signature: SignatureBound, + Public<LeftPair::Public, RightPair::Public, PUBLIC_KEY_LEN>: CryptoType, + Signature<LeftPair::Signature, RightPair::Signature, SIGNATURE_LEN>: 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<LeftPair::Public, RightPair::Public, PUBLIC_KEY_LEN>; type Signature = Signature<LeftPair::Signature, RightPair::Signature, SIGNATURE_LEN>; fn from_seed_slice(seed_slice: &[u8]) -> Result<Self, SecretStringError> { - 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() != 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<Iter: Iterator<Item = DeriveJunction>>( - &self, - path: Iter, - seed: Option<Self::Seed>, + &self, + path: Iter, + seed: Option<Self::Seed>, ) -> Result<(Self, Option<Self::Seed>), DeriveError> { - - let seed_left_right = match seed { - Some(seed) => (Some(seed.left), Some(seed.right)), - 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), - // }; - - 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(); // 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} + 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 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()); - 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<M: AsRef<[u8]>>(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<M: AsRef<[u8]>>(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 for this key. + /// Get the seed/secret key for each key and then concatenate them. fn to_raw_vec(&self) -> Vec<u8> { [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; - #[test] fn default_phrase_should_be_used() { assert_eq!( @@ -590,35 +684,38 @@ mod 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())); + #[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!("a4f2269333b3e87c577aa00c4a2cd650b3b30b2e8c286a47c251279ff3a26e0d")].concat() + [ + hex!("b8eefc4937200a8382d00050e050ced2d4ab72cc2ef1b061477afb51564fdd61"), + hex!("3a0626d095148813cd1642d38254f1cfff7eb8cc1a2fc83b2a135377c3554c12") + ] + .concat() ); } - - #[test] + #[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 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); @@ -628,18 +725,19 @@ mod test { #[test] fn test_vector_by_string_should_work() { - let pair = Pair::from_string("0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f609d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", + let pair = Pair::from_string( + "0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", None, ) .unwrap(); - let public = pair.public(); - assert_eq!( - public, - Public::unchecked_from( - hex!("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd916dc6be608fab3c6bd894a606be86db346cc170db85c733853a371f3db54ae1b12052c0888d472760c81b537572a26f00db865e5963aef8634f9917571c51b538b564b2a9ceda938c8b930969ee3b832448e08e33a79e9ddd28af419a3ce45300f5dbc768b067781f44f3fe05a19e6b07b1c4196151ec3f8ea37e4f89a8963030d2101e931276bb9ebe1f20102239d780" + 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); @@ -647,7 +745,7 @@ mod test { assert!(Pair::verify(&signature, &message[..], &public)); } - #[test] + #[test] fn generated_pair_should_work() { let (pair, _) = Pair::generate(); let public = pair.public(); @@ -657,20 +755,20 @@ mod test { assert!(!Pair::verify(&signature, b"Something else", &public)); } - - #[test] + #[test] fn seeded_pair_should_work() { - let pair = Pair::from_seed(&(b"1234567890123456789012345678901212345678901234567890123456789012".as_slice().try_into().unwrap())); + let pair = + Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap())); let public = pair.public(); assert_eq!( - public, - Public::unchecked_from( - hex!("035676109c54b9a16d271abeb4954316a40a32bcce023ac14c8e26e958aa68fba9754d2f2bbfa67df54d7e0e951979a18a1e0f45948857752cc2bac6bbb0b1d05e8e48bcc453920bf0c4bbd5993212480112a1fb433f04d74af0a8b700d93dc957ab3207f8d071e948f5aca1a7632c00bdf6d06be05b43e2e6216dccc8a5d55a0071cb2313cfd60b7e9114619cd17c06843b352f0b607a99122f6651df8f02e1ad3697bd208e62af047ddd7b942ba80080") + public, + Public::unchecked_from( + hex!("035676109c54b9a16d271abeb4954316a40a32bcce023ac14c8e26e958aa68fba9754d2f2bbfa67df54d7e0e951979a18a1e0f45948857752cc2bac6bbb0b1d05e8e48bcc453920bf0c4bbd5993212480112a1fb433f04d74af0a8b700d93dc957ab3207f8d071e948f5aca1a7632c00bdf6d06be05b43e2e6216dccc8a5d55a0071cb2313cfd60b7e9114619cd17c06843b352f0b607a99122f6651df8f02e1ad3697bd208e62af047ddd7b942ba80080") ), - ); + ); let message = - hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000" - ); + hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000" + ); let signature = pair.sign(&message[..]); println!("Correct signature: {:?}", signature); assert!(Pair::verify(&signature, &message[..], &public)); @@ -702,8 +800,9 @@ mod test { } #[test] - fn ss58check_roundtrip_works() { - let pair = Pair::from_seed(&(b"1234567890123456789012345678901212345678901234567890123456789012".as_slice().try_into().unwrap())); + 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); @@ -713,12 +812,13 @@ mod test { #[test] fn signature_serialization_works() { - let pair = Pair::from_seed(&(b"1234567890123456789012345678901212345678901234567890123456789012".as_slice().try_into().unwrap())); + let pair = + Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap())); let message = b"Something important"; - let signature = pair.sign(&message[..]); + let signature = pair.sign(&message[..]); - let serialized_signature = serde_json::to_string(&signature).unwrap(); - println!("{:?} -- {:}", signature.inner, serialized_signature); + 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(); From 7c0265859e1160a7ef12bfb8542ff2c413838767 Mon Sep 17 00:00:00 2001 From: Skalman <skalman@riseup.net> Date: Mon, 25 Sep 2023 16:33:30 -0400 Subject: [PATCH 13/30] =?UTF-8?q?replace=20`hex!`=20=E2=86=92=20`array=5Fb?= =?UTF-8?q?ytes::hex2xx`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../primitives/core/src/paired_crypto.rs | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 968930b73d511..aa9df4d991a6d 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -672,7 +672,6 @@ mod test { use super::*; use crate::crypto::DEV_PHRASE; use ecdsa_n_bls377::{Pair, Signature}; - use hex_literal::hex; #[test] fn default_phrase_should_be_used() { @@ -686,8 +685,8 @@ mod test { #[test] fn seed_and_derive_should_work() { - let seed_for_right_and_left = - hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); + let seed_for_right_and_left: [u8; SECURE_SEED_LEN] = + array_bytes::hex2array_unchecked("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); @@ -696,8 +695,8 @@ mod test { assert_eq!( derived.to_raw_vec(), [ - hex!("b8eefc4937200a8382d00050e050ced2d4ab72cc2ef1b061477afb51564fdd61"), - hex!("3a0626d095148813cd1642d38254f1cfff7eb8cc1a2fc83b2a135377c3554c12") + array_bytes::hex2array_unchecked::<&str, SECURE_SEED_LEN>("b8eefc4937200a8382d00050e050ced2d4ab72cc2ef1b061477afb51564fdd61"), + array_bytes::hex2array_unchecked::<&str, SECURE_SEED_LEN>("3a0626d095148813cd1642d38254f1cfff7eb8cc1a2fc83b2a135377c3554c12") ] .concat() ); @@ -705,19 +704,19 @@ mod test { #[test] fn test_vector_should_work() { - let seed_left_and_right = - hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); + let seed_left_and_right: [u8; SECURE_SEED_LEN] = + array_bytes::hex2array_unchecked("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" + array_bytes::hex2array_unchecked("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd917a84ca8ce4c37c93c95ecee6a3c0c9a7b9c225093cf2f12dc4f69cbfb847ef9424a18f5755d5a742247d386ff2aabb806bcf160eff31293ea9616976628f77266c8a8cc1d8753be04197bd6cdd8c5c87a148f782c4c1568d599b48833fd539001e580cff64bbc71850605433fcd051f3afc3b74819786f815ffb5272030a8d03e5df61e6183f8fd8ea85f26defa83400" ), ), ); let message = b""; - let signature = hex!("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00d1e3013161991e142d8751017d4996209c2ff8a9ee160f373733eda3b4b785ba6edce9f45f87104bbe07aa6aa6eb2780aa705efb2c13d3b317d6409d159d23bdc7cdd5c2a832d1551cf49d811d49c901495e527dbd532e3a462335ce2686009104aba7bc11c5b22be78f3198d2727a0b"); + let signature = array_bytes::hex2array_unchecked("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00d1e3013161991e142d8751017d4996209c2ff8a9ee160f373733eda3b4b785ba6edce9f45f87104bbe07aa6aa6eb2780aa705efb2c13d3b317d6409d159d23bdc7cdd5c2a832d1551cf49d811d49c901495e527dbd532e3a462335ce2686009104aba7bc11c5b22be78f3198d2727a0b"); let signature = Signature::unchecked_from(signature); assert!(pair.sign(&message[..]) == signature); assert!(Pair::verify(&signature, &message[..], &public)); @@ -734,12 +733,12 @@ mod test { assert_eq!( public, Public::unchecked_from( - hex!("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd916dc6be608fab3c6bd894a606be86db346cc170db85c733853a371f3db54ae1b12052c0888d472760c81b537572a26f00db865e5963aef8634f9917571c51b538b564b2a9ceda938c8b930969ee3b832448e08e33a79e9ddd28af419a3ce45300f5dbc768b067781f44f3fe05a19e6b07b1c4196151ec3f8ea37e4f89a8963030d2101e931276bb9ebe1f20102239d780" + array_bytes::hex2array_unchecked("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd916dc6be608fab3c6bd894a606be86db346cc170db85c733853a371f3db54ae1b12052c0888d472760c81b537572a26f00db865e5963aef8634f9917571c51b538b564b2a9ceda938c8b930969ee3b832448e08e33a79e9ddd28af419a3ce45300f5dbc768b067781f44f3fe05a19e6b07b1c4196151ec3f8ea37e4f89a8963030d2101e931276bb9ebe1f20102239d780" ), ), ); let message = b""; - let signature = hex!("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00bbb395bbdee1a35930912034f5fde3b36df2835a0536c865501b0675776a1d5931a3bea2e66eff73b2546c6af2061a8019223e4ebbbed661b2538e0f5823f2c708eb89c406beca8fcb53a5c13dbc7c0c42e4cf2be2942bba96ea29297915a06bd2b1b979c0e2ac8fd4ec684a6b5d110c"); + let signature = array_bytes::hex2array_unchecked("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00bbb395bbdee1a35930912034f5fde3b36df2835a0536c865501b0675776a1d5931a3bea2e66eff73b2546c6af2061a8019223e4ebbbed661b2538e0f5823f2c708eb89c406beca8fcb53a5c13dbc7c0c42e4cf2be2942bba96ea29297915a06bd2b1b979c0e2ac8fd4ec684a6b5d110c"); let signature = Signature::unchecked_from(signature); assert!(pair.sign(&message[..]) == signature); assert!(Pair::verify(&signature, &message[..], &public)); @@ -763,11 +762,11 @@ mod test { assert_eq!( public, Public::unchecked_from( - hex!("035676109c54b9a16d271abeb4954316a40a32bcce023ac14c8e26e958aa68fba9754d2f2bbfa67df54d7e0e951979a18a1e0f45948857752cc2bac6bbb0b1d05e8e48bcc453920bf0c4bbd5993212480112a1fb433f04d74af0a8b700d93dc957ab3207f8d071e948f5aca1a7632c00bdf6d06be05b43e2e6216dccc8a5d55a0071cb2313cfd60b7e9114619cd17c06843b352f0b607a99122f6651df8f02e1ad3697bd208e62af047ddd7b942ba80080") + array_bytes::hex2array_unchecked("035676109c54b9a16d271abeb4954316a40a32bcce023ac14c8e26e958aa68fba9754d2f2bbfa67df54d7e0e951979a18a1e0f45948857752cc2bac6bbb0b1d05e8e48bcc453920bf0c4bbd5993212480112a1fb433f04d74af0a8b700d93dc957ab3207f8d071e948f5aca1a7632c00bdf6d06be05b43e2e6216dccc8a5d55a0071cb2313cfd60b7e9114619cd17c06843b352f0b607a99122f6651df8f02e1ad3697bd208e62af047ddd7b942ba80080") ), ); let message = - hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000" + array_bytes::hex2bytes_unchecked("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000" ); let signature = pair.sign(&message[..]); println!("Correct signature: {:?}", signature); From 7f8d958e731cf6c7501309135530a49dae1b8c46 Mon Sep 17 00:00:00 2001 From: drskalman <35698397+drskalman@users.noreply.github.com> Date: Thu, 5 Oct 2023 14:44:56 -0400 Subject: [PATCH 14/30] Apply suggestions from `paired_crypto` code review on type nam, hash and SCALE. Co-authored-by: Davide Galassi <davxy@datawok.net> --- substrate/primitives/core/src/paired_crypto.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index aa9df4d991a6d..313e56ae5388e 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -110,7 +110,7 @@ pub trait PublicKeyBound: } impl< - PublicKeyTrait: TraitPublic + T: TraitPublic + Sized + Derive + sp_std::hash::Hash @@ -118,13 +118,13 @@ impl< + for<'a> TryFrom<&'a [u8]> + AsMut<[u8]> + CryptoType, - > PublicKeyBound for PublicKeyTrait + > PublicKeyBound for T { } /// A public key. #[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq, PartialOrd, Ord)] -#[scale_info(skip_type_params(T))] +#[scale_info(skip_type_params(LeftPublic, RightPublic))] pub struct Public< LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, @@ -152,8 +152,7 @@ impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RI sp_std::hash::Hash for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> { fn hash<H: sp_std::hash::Hasher>(&self, state: &mut H) { - self.left.hash(state); - self.right.hash(state); + self.inner.hash(state); } } @@ -359,14 +358,11 @@ impl< /// 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]> {} -impl<SignatureTrait: sp_std::hash::Hash + for<'a> TryFrom<&'a [u8]> + AsRef<[u8]>> SignatureBound - for SignatureTrait -{ -} +impl<T: sp_std::hash::Hash + for<'a> TryFrom<&'a [u8]> + AsRef<[u8]>> SignatureBound for T {} /// A pair of signatures of different types #[derive(Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq)] -#[scale_info(skip_type_params(T))] +#[scale_info(skip_type_params(LeftSignature, RightSignature))] pub struct Signature< LeftSignature: SignatureBound, RightSignature: SignatureBound, From eef2cec53dda1ec962498b6e3a349239e83e2881 Mon Sep 17 00:00:00 2001 From: drskalman <35698397+drskalman@users.noreply.github.com> Date: Thu, 5 Oct 2023 14:59:14 -0400 Subject: [PATCH 15/30] Do not panic in `paired::Signature::try_from` Co-authored-by: Davide Galassi <davxy@datawok.net> --- substrate/primitives/core/src/paired_crypto.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 313e56ae5388e..da0ff179045e9 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -406,8 +406,8 @@ where if data.len() != LEFT_PLUS_RIGHT_LEN { return Err(()); } - let Ok(left) : Result<LeftSignature, _> = data[0..Self::LEFT_SIGNATURE_LEN].try_into() else { panic!("invalid signature") }; - let Ok(right) : Result<RightSignature, _>= data[Self::LEFT_SIGNATURE_LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { panic!("invalid signature") }; + let left: LeftSignature = data[0..Self::LEFT_SIGNATURE_LEN].try_into().map_err(|_| ())?; + let right: RightSignature = data[Self::LEFT_SIGNATURE_LEN..LEFT_PLUS_RIGHT_LEN].try_into().map_err(|_| ())?; let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; inner[..Self::LEFT_SIGNATURE_LEN].copy_from_slice(left.as_ref()); From efb215f78ea95346e4f07fa4a2801d83e575d1fe Mon Sep 17 00:00:00 2001 From: drskalman <35698397+drskalman@users.noreply.github.com> Date: Thu, 5 Oct 2023 15:00:27 -0400 Subject: [PATCH 16/30] Remove `DoublePair` trait. Co-authored-by: Davide Galassi <davxy@datawok.net> --- substrate/primitives/core/src/paired_crypto.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index da0ff179045e9..93a052be100cd 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -556,10 +556,6 @@ pub struct Pair< right: RightPair, } -trait DoublePair { - const PUBLIC_KEY_LEN: usize; - const SIGNATURE_LEN: usize; -} #[cfg(feature = "full_crypto")] impl< From 65584bd7c58229caaa390f2d9bfb7d242f82198b Mon Sep 17 00:00:00 2001 From: drskalman <35698397+drskalman@users.noreply.github.com> Date: Thu, 5 Oct 2023 15:01:53 -0400 Subject: [PATCH 17/30] Do not empty implement `paired::Pair` Co-authored-by: Davide Galassi <davxy@datawok.net> --- substrate/primitives/core/src/paired_crypto.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 93a052be100cd..e04ead798f720 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -557,15 +557,6 @@ pub struct Pair< } -#[cfg(feature = "full_crypto")] -impl< - LeftPair: TraitPair, - RightPair: TraitPair, - const PUBLIC_KEY_LEN: usize, - const SIGNATURE_LEN: usize, - > Pair<LeftPair, RightPair, PUBLIC_KEY_LEN, SIGNATURE_LEN> -{ -} #[cfg(feature = "full_crypto")] impl< From e047f75a52fda8d9ebc10b4a06558e1cc1b1cf37 Mon Sep 17 00:00:00 2001 From: drskalman <35698397+drskalman@users.noreply.github.com> Date: Thu, 5 Oct 2023 15:17:46 -0400 Subject: [PATCH 18/30] Use `paired_crypto::Seed` instead of `[u8; SECURE_SEED_LEN]` Co-authored-by: Davide Galassi <davxy@datawok.net> --- substrate/primitives/core/src/paired_crypto.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index e04ead798f720..50983ec5eb59b 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -571,8 +571,8 @@ where RightPair::Signature: SignatureBound, Public<LeftPair::Public, RightPair::Public, PUBLIC_KEY_LEN>: CryptoType, Signature<LeftPair::Signature, RightPair::Signature, SIGNATURE_LEN>: 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]>, + LeftPair::Seed: From<Seed> + Into<Seed>, + RightPair::Seed: From<Seed> + Into<Seed>, { type Seed = Seed; type Public = Public<LeftPair::Public, RightPair::Public, PUBLIC_KEY_LEN>; From c12b82e24d16aa813314b4ec74bf0923eee63714 Mon Sep 17 00:00:00 2001 From: Skalman <skalman@riseup.net> Date: Thu, 5 Oct 2023 15:08:34 -0400 Subject: [PATCH 19/30] use `ecdsa::PUBLIC_KEY_SERIALIZED_SIZE` and `ecdsa::SIGNATURE_SERIALIZED_SIZE` instead of magic numbers --- substrate/primitives/core/src/ecdsa.rs | 50 +++++++++++-------- .../primitives/core/src/paired_crypto.rs | 4 +- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/substrate/primitives/core/src/ecdsa.rs b/substrate/primitives/core/src/ecdsa.rs index 05bc679386c3d..ee047e0410df5 100644 --- a/substrate/primitives/core/src/ecdsa.rs +++ b/substrate/primitives/core/src/ecdsa.rs @@ -50,6 +50,12 @@ use sp_std::vec::Vec; /// An identifier used to match public keys against ecdsa keys pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecds"); +/// The byte length of public key +pub const PUBLIC_KEY_SERIALIZED_SIZE :usize = 33; + +/// The byte length of public key +pub const SIGNATURE_SERIALIZED_SIZE: usize = 65; + /// A secret seed (which is bytewise essentially equivalent to a SecretKey). /// /// We need it as a different type because `Seed` is expected to be AsRef<[u8]>. @@ -71,11 +77,11 @@ type Seed = [u8; 32]; PartialOrd, Ord, )] -pub struct Public(pub [u8; 33]); +pub struct Public(pub [u8; PUBLIC_KEY_SERIALIZED_SIZE]); impl crate::crypto::FromEntropy for Public { fn from_entropy(input: &mut impl codec::Input) -> Result<Self, codec::Error> { - let mut result = Self([0u8; 33]); + let mut result = Self([0u8; PUBLIC_KEY_SERIALIZED_SIZE]); input.read(&mut result.0[..])?; Ok(result) } @@ -86,7 +92,7 @@ impl Public { /// /// NOTE: No checking goes on to ensure this is a real public key. Only use it if /// you are certain that the array actually is a pubkey. GIGO! - pub fn from_raw(data: [u8; 33]) -> Self { + pub fn from_raw(data: [u8; PUBLIC_KEY_SERIALIZED_SIZE]) -> Self { Self(data) } @@ -109,7 +115,7 @@ impl Public { } impl ByteArray for Public { - const LEN: usize = 33; + const LEN: usize = PUBLIC_KEY_SERIALIZED_SIZE; } impl TraitPublic for Public {} @@ -148,8 +154,8 @@ impl From<Pair> for Public { } } -impl UncheckedFrom<[u8; 33]> for Public { - fn unchecked_from(x: [u8; 33]) -> Self { +impl UncheckedFrom<[u8; PUBLIC_KEY_SERIALIZED_SIZE]> for Public { + fn unchecked_from(x: [u8; PUBLIC_KEY_SERIALIZED_SIZE]) -> Self { Public(x) } } @@ -198,14 +204,14 @@ impl<'de> Deserialize<'de> for Public { /// A signature (a 512-bit value, plus 8 bits for recovery ID). #[cfg_attr(feature = "full_crypto", derive(Hash))] #[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq)] -pub struct Signature(pub [u8; 65]); +pub struct Signature(pub [u8; SIGNATURE_SERIALIZED_SIZE]); impl TryFrom<&[u8]> for Signature { type Error = (); fn try_from(data: &[u8]) -> Result<Self, Self::Error> { - if data.len() == 65 { - let mut inner = [0u8; 65]; + if data.len() == SIGNATURE_SERIALIZED_SIZE { + let mut inner = [0u8; SIGNATURE_SERIALIZED_SIZE]; inner.copy_from_slice(data); Ok(Signature(inner)) } else { @@ -239,7 +245,7 @@ impl<'de> Deserialize<'de> for Signature { impl Clone for Signature { fn clone(&self) -> Self { - let mut r = [0u8; 65]; + let mut r = [0u8; SIGNATURE_SERIALIZED_SIZE]; r.copy_from_slice(&self.0[..]); Signature(r) } @@ -247,18 +253,18 @@ impl Clone for Signature { impl Default for Signature { fn default() -> Self { - Signature([0u8; 65]) + Signature([0u8; SIGNATURE_SERIALIZED_SIZE]) } } -impl From<Signature> for [u8; 65] { - fn from(v: Signature) -> [u8; 65] { +impl From<Signature> for [u8; SIGNATURE_SERIALIZED_SIZE] { + fn from(v: Signature) -> [u8; SIGNATURE_SERIALIZED_SIZE] { v.0 } } -impl AsRef<[u8; 65]> for Signature { - fn as_ref(&self) -> &[u8; 65] { +impl AsRef<[u8; SIGNATURE_SERIALIZED_SIZE]> for Signature { + fn as_ref(&self) -> &[u8; SIGNATURE_SERIALIZED_SIZE] { &self.0 } } @@ -287,8 +293,8 @@ impl sp_std::fmt::Debug for Signature { } } -impl UncheckedFrom<[u8; 65]> for Signature { - fn unchecked_from(data: [u8; 65]) -> Signature { +impl UncheckedFrom<[u8; SIGNATURE_SERIALIZED_SIZE]> for Signature { + fn unchecked_from(data: [u8; SIGNATURE_SERIALIZED_SIZE]) -> Signature { Signature(data) } } @@ -298,7 +304,7 @@ impl Signature { /// /// NOTE: No checking goes on to ensure this is a real signature. Only use it if /// you are certain that the array actually is a signature. GIGO! - pub fn from_raw(data: [u8; 65]) -> Signature { + pub fn from_raw(data: [u8; SIGNATURE_SERIALIZED_SIZE]) -> Signature { Signature(data) } @@ -307,10 +313,10 @@ impl Signature { /// NOTE: No checking goes on to ensure this is a real signature. Only use it if /// you are certain that the array actually is a signature. GIGO! pub fn from_slice(data: &[u8]) -> Option<Self> { - if data.len() != 65 { + if data.len() != SIGNATURE_SERIALIZED_SIZE { return None } - let mut r = [0u8; 65]; + let mut r = [0u8; SIGNATURE_SERIALIZED_SIZE]; r.copy_from_slice(data); Some(Signature(r)) } @@ -473,7 +479,7 @@ impl Pair { pub fn verify_deprecated<M: AsRef<[u8]>>(sig: &Signature, message: M, pubkey: &Public) -> bool { let message = libsecp256k1::Message::parse(&blake2_256(message.as_ref())); - let parse_signature_overflowing = |x: [u8; 65]| { + let parse_signature_overflowing = |x: [u8; SIGNATURE_SERIALIZED_SIZE]| { let sig = libsecp256k1::Signature::parse_overflowing_slice(&x[..64]).ok()?; let rid = libsecp256k1::RecoveryId::parse(x[64]).ok()?; Some((sig, rid)) @@ -726,7 +732,7 @@ mod test { let signature = pair.sign(&message[..]); let serialized_signature = serde_json::to_string(&signature).unwrap(); // Signature is 65 bytes, so 130 chars + 2 quote chars - assert_eq!(serialized_signature.len(), 132); + assert_eq!(serialized_signature.len(), SIGNATURE_SERIALIZED_SIZE * 2 + 2); let signature = serde_json::from_str(&serialized_signature).unwrap(); assert!(Pair::verify(&signature, &message[..], &pair.public())); } diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 50983ec5eb59b..4188cd848e194 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -43,8 +43,8 @@ pub mod ecdsa_n_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 PUBLIC_KEY_LEN: usize = crate::ecdsa::PUBLIC_KEY_SERIALIZED_SIZE + crate::bls::PUBLIC_KEY_SERIALIZED_SIZE; + const LEFT_SIGNATURE_LEN: usize = crate::ecdsa::SIGNATURE_SERIALIZED_SIZE; const RIGHT_SIGNATURE_LEN: usize = crate::bls::SIGNATURE_SERIALIZED_SIZE; const SIGNATURE_LEN: usize = LEFT_SIGNATURE_LEN + RIGHT_SIGNATURE_LEN; From dba854a7ef736341c051954edcb023628c553e33 Mon Sep 17 00:00:00 2001 From: Skalman <skalman@riseup.net> Date: Thu, 5 Oct 2023 15:20:34 -0400 Subject: [PATCH 20/30] Remove `paired::DoublePair` impl as well --- substrate/primitives/core/src/paired_crypto.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 4188cd848e194..d9401be8a5407 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -62,12 +62,6 @@ pub mod ecdsa_n_bls377 { 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; @@ -566,7 +560,7 @@ impl< const SIGNATURE_LEN: usize, > TraitPair for Pair<LeftPair, RightPair, PUBLIC_KEY_LEN, SIGNATURE_LEN> where - Pair<LeftPair, RightPair, PUBLIC_KEY_LEN, SIGNATURE_LEN>: DoublePair + CryptoType, + Pair<LeftPair, RightPair, PUBLIC_KEY_LEN, SIGNATURE_LEN>: CryptoType, LeftPair::Signature: SignatureBound, RightPair::Signature: SignatureBound, Public<LeftPair::Public, RightPair::Public, PUBLIC_KEY_LEN>: CryptoType, From 5182c8616b3f68a56f647260370d336429910f94 Mon Sep 17 00:00:00 2001 From: Skalman <skalman@riseup.net> Date: Thu, 5 Oct 2023 15:46:46 -0400 Subject: [PATCH 21/30] - Implement `BytesArray` for both ecdsa and bls Signatures - Remove `SignaturePair` trait. - Skip encoding redundant copy of paired::Public and Signature and implement Decode --- substrate/primitives/core/src/bls.rs | 4 ++ substrate/primitives/core/src/ecdsa.rs | 4 ++ .../primitives/core/src/paired_crypto.rs | 72 +++++++++++-------- 3 files changed, 50 insertions(+), 30 deletions(-) diff --git a/substrate/primitives/core/src/bls.rs b/substrate/primitives/core/src/bls.rs index 8e9f8ec356a98..e3c21832a19bc 100644 --- a/substrate/primitives/core/src/bls.rs +++ b/substrate/primitives/core/src/bls.rs @@ -317,6 +317,10 @@ impl<T> sp_std::hash::Hash for Signature<T> { } } +impl<T> ByteArray for Signature<T> { + const LEN: usize = SIGNATURE_SERIALIZED_SIZE; +} + impl<T> TryFrom<&[u8]> for Signature<T> { type Error = (); diff --git a/substrate/primitives/core/src/ecdsa.rs b/substrate/primitives/core/src/ecdsa.rs index ee047e0410df5..1cdf24ac828c1 100644 --- a/substrate/primitives/core/src/ecdsa.rs +++ b/substrate/primitives/core/src/ecdsa.rs @@ -206,6 +206,10 @@ impl<'de> Deserialize<'de> for Public { #[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq)] pub struct Signature(pub [u8; SIGNATURE_SERIALIZED_SIZE]); +impl ByteArray for Signature { + const LEN: usize = SIGNATURE_SERIALIZED_SIZE; +} + impl TryFrom<&[u8]> for Signature { type Error = (); diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index d9401be8a5407..2c098b604d80b 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -56,12 +56,6 @@ pub mod ecdsa_n_bls377 { /// (ECDSA, BLS12-377) signature pair. pub type Signature = super::Signature<ecdsa::Signature, bls377::Signature, SIGNATURE_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; - } - impl super::CryptoType for Public { #[cfg(feature = "full_crypto")] type Pair = Pair; @@ -117,18 +111,32 @@ impl< } /// A public key. -#[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Encode, MaxEncodedLen, TypeInfo, PartialEq, Eq, PartialOrd, Ord)] #[scale_info(skip_type_params(LeftPublic, RightPublic))] pub struct Public< LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize, > { + #[codec(skip)] left: LeftPublic, + #[codec(skip)] right: RightPublic, inner: [u8; LEFT_PLUS_RIGHT_LEN], } +impl< + LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize + > Decode for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> +{ + fn decode<R: codec::Input>(i: &mut R) -> Result<Self, codec::Error> { + let buf = <[u8; LEFT_PLUS_RIGHT_LEN]>::decode(i)?; + buf.as_slice() + .try_into() + .map_err(|_| codec::Error::from("invalid public key data")) + } +} + // 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. // impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> { // inline fn left<'a>(&self)-> &'a LeftPublic { @@ -141,6 +149,7 @@ pub struct Public< // } + #[cfg(feature = "full_crypto")] impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> sp_std::hash::Hash for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> @@ -350,27 +359,37 @@ impl< } /// 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]> + ByteArray {} -impl<T: sp_std::hash::Hash + for<'a> TryFrom<&'a [u8]> + AsRef<[u8]>> SignatureBound for T {} +impl<T: sp_std::hash::Hash + for<'a> TryFrom<&'a [u8]> + AsRef<[u8]> + ByteArray> SignatureBound for T {} /// A pair of signatures of different types -#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq)] +#[derive(Encode, MaxEncodedLen, TypeInfo, PartialEq, Eq)] #[scale_info(skip_type_params(LeftSignature, RightSignature))] pub struct Signature< LeftSignature: SignatureBound, RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize, > { + #[codec(skip)] left: LeftSignature, + #[codec(skip)] 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; +impl< + LeftSignature: SignatureBound, + RightSignature: SignatureBound, + const LEFT_PLUS_RIGHT_LEN: usize, + > Decode for Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN> +{ + fn decode<R: codec::Input>(i: &mut R) -> Result<Self, codec::Error> { + let buf = <[u8; LEFT_PLUS_RIGHT_LEN]>::decode(i)?; + buf.as_slice() + .try_into() + .map_err(|_| codec::Error::from("invalid signature data")) + } } #[cfg(feature = "full_crypto")] @@ -391,8 +410,6 @@ impl< RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize, > TryFrom<&[u8]> for Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN> -where - Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN>: SignaturePair, { type Error = (); @@ -400,12 +417,12 @@ where if data.len() != LEFT_PLUS_RIGHT_LEN { return Err(()); } - let left: LeftSignature = data[0..Self::LEFT_SIGNATURE_LEN].try_into().map_err(|_| ())?; - let right: RightSignature = data[Self::LEFT_SIGNATURE_LEN..LEFT_PLUS_RIGHT_LEN].try_into().map_err(|_| ())?; + let left: LeftSignature = data[0..LeftSignature::LEN].try_into().map_err(|_| ())?; + let right: RightSignature = data[LeftSignature::LEN..LEFT_PLUS_RIGHT_LEN].try_into().map_err(|_| ())?; 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()); + inner[..LeftSignature::LEN].copy_from_slice(left.as_ref()); + inner[LeftSignature::LEN..].copy_from_slice(right.as_ref()); Ok(Signature { left, right, inner }) } @@ -466,8 +483,6 @@ impl< RightSignature: SignatureBound, const LEFT_PLUS_RIGHT_LEN: usize, > Deserialize<'de> for Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN> -where - Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN>: SignaturePair, { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where @@ -526,12 +541,10 @@ impl< const LEFT_PLUS_RIGHT_LEN: usize, > UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]> for Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN> -where - Signature<LeftSignature, RightSignature, LEFT_PLUS_RIGHT_LEN>: 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..LeftSignature::LEN].try_into() else { panic!("invalid signature") }; + let Ok(right) = data[LeftSignature::LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { panic!("invalid signature") }; Signature { left, right, inner: data } } @@ -564,7 +577,6 @@ where LeftPair::Signature: SignatureBound, RightPair::Signature: SignatureBound, Public<LeftPair::Public, RightPair::Public, PUBLIC_KEY_LEN>: CryptoType, - Signature<LeftPair::Signature, RightPair::Signature, SIGNATURE_LEN>: SignaturePair, LeftPair::Seed: From<Seed> + Into<Seed>, RightPair::Seed: From<Seed> + Into<Seed>, { @@ -624,8 +636,8 @@ where 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()); + r[..LeftPair::Signature::LEN].copy_from_slice(self.left.sign(message).as_ref()); + r[LeftPair::Signature::LEN..].copy_from_slice(self.right.sign(message).as_ref()); Self::Signature::unchecked_from(r) } @@ -795,7 +807,7 @@ mod test { 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 + // Signature is 177 bytes, hexify * 2 + 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())); From 17d0077b5681c95a6d1a8c0d4d045e4a4acf15c9 Mon Sep 17 00:00:00 2001 From: Skalman <skalman@riseup.net> Date: Thu, 5 Oct 2023 15:59:47 -0400 Subject: [PATCH 22/30] Implement encode_and_decode_(public_key/signature)_works test for paired_crypto::Pair --- .../primitives/core/src/paired_crypto.rs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 2c098b604d80b..a2e7942f6b47f 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -823,4 +823,25 @@ mod test { // Poorly-sized assert!(deserialize_signature("\"abc123\"").is_err()); } + + #[test] + fn encode_and_decode_public_key_works() { + let pair = + Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap())); + let public = pair.public(); + let encoded_public = public.encode(); + let decoded_public = Public::decode(&mut encoded_public.as_slice()).unwrap(); + assert_eq!(public, decoded_public) + } + + #[test] + fn encode_and_decode_signature_works() { + let pair = + Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap())); + let message = b"Something important"; + let signature = pair.sign(&message[..]); + let encoded_signature = signature.encode(); + let decoded_signature = Signature::decode(&mut encoded_signature.as_slice()).unwrap(); + assert_eq!(signature, decoded_signature) + } } From a7405895f25f8bcb98b3eac7978123f20285f987 Mon Sep 17 00:00:00 2001 From: Skalman <skalman@riseup.net> Date: Thu, 5 Oct 2023 16:04:38 -0400 Subject: [PATCH 23/30] cargo fmt --- substrate/primitives/core/src/bls.rs | 6 +- substrate/primitives/core/src/ecdsa.rs | 6 +- .../primitives/core/src/paired_crypto.rs | 70 +++++++++++-------- 3 files changed, 47 insertions(+), 35 deletions(-) diff --git a/substrate/primitives/core/src/bls.rs b/substrate/primitives/core/src/bls.rs index e3c21832a19bc..7cb788f14c076 100644 --- a/substrate/primitives/core/src/bls.rs +++ b/substrate/primitives/core/src/bls.rs @@ -200,7 +200,7 @@ impl<T> TryFrom<&[u8]> for Public<T> { fn try_from(data: &[u8]) -> Result<Self, Self::Error> { if data.len() != PUBLIC_KEY_SERIALIZED_SIZE { - return Err(()) + return Err(()); } let mut r = [0u8; PUBLIC_KEY_SERIALIZED_SIZE]; r.copy_from_slice(data); @@ -326,7 +326,7 @@ impl<T> TryFrom<&[u8]> for Signature<T> { fn try_from(data: &[u8]) -> Result<Self, Self::Error> { if data.len() != SIGNATURE_SERIALIZED_SIZE { - return Err(()) + return Err(()); } let mut inner = [0u8; SIGNATURE_SERIALIZED_SIZE]; inner.copy_from_slice(data); @@ -436,7 +436,7 @@ impl<T: BlsBound> TraitPair for Pair<T> { fn from_seed_slice(seed_slice: &[u8]) -> Result<Self, SecretStringError> { if seed_slice.len() != SECRET_KEY_SERIALIZED_SIZE { - return Err(SecretStringError::InvalidSeedLength) + return Err(SecretStringError::InvalidSeedLength); } let secret = w3f_bls::SecretKey::from_seed(seed_slice); let public = secret.into_public(); diff --git a/substrate/primitives/core/src/ecdsa.rs b/substrate/primitives/core/src/ecdsa.rs index 1cdf24ac828c1..3e27acf5b739a 100644 --- a/substrate/primitives/core/src/ecdsa.rs +++ b/substrate/primitives/core/src/ecdsa.rs @@ -51,7 +51,7 @@ use sp_std::vec::Vec; pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecds"); /// The byte length of public key -pub const PUBLIC_KEY_SERIALIZED_SIZE :usize = 33; +pub const PUBLIC_KEY_SERIALIZED_SIZE: usize = 33; /// The byte length of public key pub const SIGNATURE_SERIALIZED_SIZE: usize = 65; @@ -139,7 +139,7 @@ impl TryFrom<&[u8]> for Public { fn try_from(data: &[u8]) -> Result<Self, Self::Error> { if data.len() != Self::LEN { - return Err(()) + return Err(()); } let mut r = [0u8; Self::LEN]; r.copy_from_slice(data); @@ -318,7 +318,7 @@ impl Signature { /// you are certain that the array actually is a signature. GIGO! pub fn from_slice(data: &[u8]) -> Option<Self> { if data.len() != SIGNATURE_SERIALIZED_SIZE { - return None + return None; } let mut r = [0u8; SIGNATURE_SERIALIZED_SIZE]; r.copy_from_slice(data); diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index a2e7942f6b47f..2ea3e4f0387de 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -43,7 +43,8 @@ pub mod ecdsa_n_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 = crate::ecdsa::PUBLIC_KEY_SERIALIZED_SIZE + crate::bls::PUBLIC_KEY_SERIALIZED_SIZE; + const PUBLIC_KEY_LEN: usize = + crate::ecdsa::PUBLIC_KEY_SERIALIZED_SIZE + crate::bls::PUBLIC_KEY_SERIALIZED_SIZE; const LEFT_SIGNATURE_LEN: usize = crate::ecdsa::SIGNATURE_SERIALIZED_SIZE; const RIGHT_SIGNATURE_LEN: usize = crate::bls::SIGNATURE_SERIALIZED_SIZE; const SIGNATURE_LEN: usize = LEFT_SIGNATURE_LEN + RIGHT_SIGNATURE_LEN; @@ -125,9 +126,8 @@ pub struct Public< inner: [u8; LEFT_PLUS_RIGHT_LEN], } -impl< - LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize - > Decode for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> +impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> + Decode for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> { fn decode<R: codec::Input>(i: &mut R) -> Result<Self, codec::Error> { let buf = <[u8; LEFT_PLUS_RIGHT_LEN]>::decode(i)?; @@ -149,7 +149,6 @@ impl< // } - #[cfg(feature = "full_crypto")] impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> sp_std::hash::Hash for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> @@ -359,9 +358,15 @@ impl< } /// 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]> + ByteArray {} +pub trait SignatureBound: + sp_std::hash::Hash + for<'a> TryFrom<&'a [u8]> + AsRef<[u8]> + ByteArray +{ +} -impl<T: sp_std::hash::Hash + for<'a> TryFrom<&'a [u8]> + AsRef<[u8]> + ByteArray> SignatureBound for T {} +impl<T: sp_std::hash::Hash + for<'a> TryFrom<&'a [u8]> + AsRef<[u8]> + ByteArray> SignatureBound + for T +{ +} /// A pair of signatures of different types #[derive(Encode, MaxEncodedLen, TypeInfo, PartialEq, Eq)] @@ -418,7 +423,8 @@ impl< return Err(()); } let left: LeftSignature = data[0..LeftSignature::LEN].try_into().map_err(|_| ())?; - let right: RightSignature = data[LeftSignature::LEN..LEFT_PLUS_RIGHT_LEN].try_into().map_err(|_| ())?; + let right: RightSignature = + data[LeftSignature::LEN..LEFT_PLUS_RIGHT_LEN].try_into().map_err(|_| ())?; let mut inner = [0u8; LEFT_PLUS_RIGHT_LEN]; inner[..LeftSignature::LEN].copy_from_slice(left.as_ref()); @@ -544,7 +550,9 @@ impl< { fn unchecked_from(data: [u8; LEFT_PLUS_RIGHT_LEN]) -> Self { let Ok(left) = data[0..LeftSignature::LEN].try_into() else { panic!("invalid signature") }; - let Ok(right) = data[LeftSignature::LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { panic!("invalid signature") }; + let Ok(right) = data[LeftSignature::LEN..LEFT_PLUS_RIGHT_LEN].try_into() else { + panic!("invalid signature") + }; Signature { left, right, inner: data } } @@ -563,8 +571,6 @@ pub struct Pair< right: RightPair, } - - #[cfg(feature = "full_crypto")] impl< LeftPair: TraitPair, @@ -674,8 +680,9 @@ mod test { #[test] fn seed_and_derive_should_work() { - let seed_for_right_and_left: [u8; SECURE_SEED_LEN] = - array_bytes::hex2array_unchecked("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); + let seed_for_right_and_left: [u8; SECURE_SEED_LEN] = array_bytes::hex2array_unchecked( + "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); @@ -684,8 +691,12 @@ mod test { assert_eq!( derived.to_raw_vec(), [ - array_bytes::hex2array_unchecked::<&str, SECURE_SEED_LEN>("b8eefc4937200a8382d00050e050ced2d4ab72cc2ef1b061477afb51564fdd61"), - array_bytes::hex2array_unchecked::<&str, SECURE_SEED_LEN>("3a0626d095148813cd1642d38254f1cfff7eb8cc1a2fc83b2a135377c3554c12") + array_bytes::hex2array_unchecked::<&str, SECURE_SEED_LEN>( + "b8eefc4937200a8382d00050e050ced2d4ab72cc2ef1b061477afb51564fdd61" + ), + array_bytes::hex2array_unchecked::<&str, SECURE_SEED_LEN>( + "3a0626d095148813cd1642d38254f1cfff7eb8cc1a2fc83b2a135377c3554c12" + ) ] .concat() ); @@ -693,8 +704,9 @@ mod test { #[test] fn test_vector_should_work() { - let seed_left_and_right: [u8; SECURE_SEED_LEN] = - array_bytes::hex2array_unchecked("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); + let seed_left_and_right: [u8; SECURE_SEED_LEN] = array_bytes::hex2array_unchecked( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", + ); let pair = Pair::from_seed(&([seed_left_and_right].concat()[..].try_into().unwrap())); let public = pair.public(); assert_eq!( @@ -824,24 +836,24 @@ mod test { assert!(deserialize_signature("\"abc123\"").is_err()); } - #[test] - fn encode_and_decode_public_key_works() { + #[test] + fn encode_and_decode_public_key_works() { let pair = Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap())); let public = pair.public(); - let encoded_public = public.encode(); - let decoded_public = Public::decode(&mut encoded_public.as_slice()).unwrap(); - assert_eq!(public, decoded_public) - } + let encoded_public = public.encode(); + let decoded_public = Public::decode(&mut encoded_public.as_slice()).unwrap(); + assert_eq!(public, decoded_public) + } - #[test] - fn encode_and_decode_signature_works() { + #[test] + fn encode_and_decode_signature_works() { let pair = Pair::from_seed(&(b"12345678901234567890123456789012".as_slice().try_into().unwrap())); let message = b"Something important"; let signature = pair.sign(&message[..]); - let encoded_signature = signature.encode(); - let decoded_signature = Signature::decode(&mut encoded_signature.as_slice()).unwrap(); - assert_eq!(signature, decoded_signature) - } + let encoded_signature = signature.encode(); + let decoded_signature = Signature::decode(&mut encoded_signature.as_slice()).unwrap(); + assert_eq!(signature, decoded_signature) + } } From 79f25e9e717999535963fbbd7444b1d5e25e7af9 Mon Sep 17 00:00:00 2001 From: Skalman <skalman@riseup.net> Date: Fri, 6 Oct 2023 12:13:20 -0400 Subject: [PATCH 24/30] - Implement RuntimeAppCrypto and necessery hostApi for ecdsa_bls377 crypto type - Implement ecdsa_bls37_crypto for BEEFY primitives. --- .../application-crypto/src/ecdsa_bls377.rs | 56 +++++++++++++++ .../primitives/application-crypto/src/lib.rs | 2 + .../primitives/consensus/beefy/src/lib.rs | 56 +++++++++++++++ substrate/primitives/core/src/lib.rs | 2 + .../primitives/core/src/paired_crypto.rs | 13 ++-- substrate/primitives/core/src/testing.rs | 2 + substrate/primitives/io/src/lib.rs | 20 +++++- substrate/primitives/keystore/src/lib.rs | 71 ++++++++++++++++++- substrate/primitives/keystore/src/testing.rs | 26 ++++++- 9 files changed, 238 insertions(+), 10 deletions(-) create mode 100644 substrate/primitives/application-crypto/src/ecdsa_bls377.rs diff --git a/substrate/primitives/application-crypto/src/ecdsa_bls377.rs b/substrate/primitives/application-crypto/src/ecdsa_bls377.rs new file mode 100644 index 0000000000000..ae4214c9803d0 --- /dev/null +++ b/substrate/primitives/application-crypto/src/ecdsa_bls377.rs @@ -0,0 +1,56 @@ +// 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 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. + +//! BLS12-377 crypto applications. +use crate::{KeyTypeId, RuntimePublic}; + +pub use sp_core::paired_crypto::ecdsa_bls377::*; + +mod app { + crate::app_crypto!(super, sp_core::testing::ECDSA_BLS377); +} + +#[cfg(feature = "full_crypto")] +pub use app::Pair as AppPair; +pub use app::{Public as AppPublic, Signature as AppSignature}; + +impl RuntimePublic for Public { + type Signature = Signature; + + /// Dummy implementation. Returns an empty vector. + fn all(_key_type: KeyTypeId) -> Vec<Self> { + Vec::new() + } + + fn generate_pair(key_type: KeyTypeId, seed: Option<Vec<u8>>) -> Self { + sp_io::crypto::ecdsa_bls377_generate(key_type, seed) + } + + /// Dummy implementation. Returns `None`. + fn sign<M: AsRef<[u8]>>(&self, _key_type: KeyTypeId, _msg: &M) -> Option<Self::Signature> { + None + } + + /// Dummy implementation. Returns `false`. + fn verify<M: AsRef<[u8]>>(&self, _msg: &M, _signature: &Self::Signature) -> bool { + false + } + + fn to_raw_vec(&self) -> Vec<u8> { + sp_core::crypto::ByteArray::to_raw_vec(self) + } +} diff --git a/substrate/primitives/application-crypto/src/lib.rs b/substrate/primitives/application-crypto/src/lib.rs index 5384220bc9ca3..9fab4ccbdc09b 100644 --- a/substrate/primitives/application-crypto/src/lib.rs +++ b/substrate/primitives/application-crypto/src/lib.rs @@ -49,6 +49,8 @@ pub mod bandersnatch; pub mod bls377; #[cfg(feature = "bls-experimental")] pub mod bls381; +#[cfg(feature = "bls-experimental")] +pub mod ecdsa_bls377; pub mod ecdsa; pub mod ed25519; pub mod sr25519; diff --git a/substrate/primitives/consensus/beefy/src/lib.rs b/substrate/primitives/consensus/beefy/src/lib.rs index c69e26bf574d8..4a842fa42acd6 100644 --- a/substrate/primitives/consensus/beefy/src/lib.rs +++ b/substrate/primitives/consensus/beefy/src/lib.rs @@ -140,6 +140,45 @@ pub mod bls_crypto { } } } + +/// BEEFY cryptographic types for (ECDSA,BLS) crypto pair +/// +/// This module basically introduces four crypto types: +/// - `bls_crypto::Pair` +/// - `bls_crypto::Public` +/// - `bls_crypto::Signature` +/// - `bls_crypto::AuthorityId` +/// +/// Your code should use the above types as concrete types for all crypto related +/// functionality. +#[cfg(feature = "bls-experimental")] +pub mod ecdsa_bls_crypto { + use super::{BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE as BEEFY_KEY_TYPE}; + use sp_application_crypto::{app_crypto, ecdsa_bls377}; + use sp_core::{ecdsa_bls377::Pair as EcdsaBlsPair, crypto::Wraps, Pair as _}; + app_crypto!(ecdsa_bls377, BEEFY_KEY_TYPE); + + /// Identity of a BEEFY authority using BLS as its crypto. + pub type AuthorityId = Public; + + /// Signature for a BEEFY authority using BLS as its crypto. + pub type AuthoritySignature = Signature; + + impl<MsgHash: Hash> BeefyAuthorityId<MsgHash> for AuthorityId + where + <MsgHash as Hash>::Output: Into<[u8; 32]>, + { + fn verify(&self, signature: &<Self as RuntimeAppPublic>::Signature, msg: &[u8]) -> bool { + // `w3f-bls` library uses IETF hashing standard and as such does not exposes + // a choice of hash to field function. + // We are directly calling into the library to avoid introducing new host call. + // and because BeefyAuthorityId::verify is being called in the runtime so we don't have + + EcdsaBlsPair::verify(signature.as_inner_ref(), msg, self.as_inner_ref()) + } + } +} + /// The `ConsensusEngineId` of BEEFY. pub const BEEFY_ENGINE_ID: sp_runtime::ConsensusEngineId = *b"BEEF"; @@ -458,4 +497,21 @@ mod tests { let (other_pair, _) = bls_crypto::Pair::generate(); assert!(!BeefyAuthorityId::<Keccak256>::verify(&other_pair.public(), &signature, msg,)); } + + #[test] + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls_beefy_verify_works() { + let msg = &b"test-message"[..]; + let (pair, _) = ecdsa_bls_crypto::Pair::generate(); + + let signature: ecdsa_bls_crypto::Signature = pair.as_inner_ref().sign(&msg).into(); + + // Verification works if same hashing function is used when signing and verifying. + assert!(BeefyAuthorityId::<Keccak256>::verify(&pair.public(), &signature, msg)); + + // Other public key doesn't work + let (other_pair, _) = ecdsa_bls_crypto::Pair::generate(); + assert!(!BeefyAuthorityId::<Keccak256>::verify(&other_pair.public(), &signature, msg,)); + } + } diff --git a/substrate/primitives/core/src/lib.rs b/substrate/primitives/core/src/lib.rs index 7174e8b34aad9..131d4739a1b0b 100644 --- a/substrate/primitives/core/src/lib.rs +++ b/substrate/primitives/core/src/lib.rs @@ -75,6 +75,8 @@ pub mod uint; #[cfg(feature = "bls-experimental")] pub use bls::{bls377, bls381}; +#[cfg(feature = "bls-experimental")] +pub use paired_crypto::ecdsa_bls377; pub use self::{ hash::{convert_hash, H160, H256, H512}, diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 2ea3e4f0387de..e25c283da7324 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -31,12 +31,12 @@ use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; -use sp_runtime_interface::pass_by::PassByInner; +use sp_runtime_interface::pass_by::{self, PassBy, PassByInner}; use sp_std::convert::TryFrom; /// ECDSA and BLS-377 paired crypto scheme #[cfg(feature = "bls-experimental")] -pub mod ecdsa_n_bls377 { +pub mod ecdsa_bls377 { use crate::crypto::CryptoTypeId; use crate::{bls377, ecdsa}; @@ -227,6 +227,11 @@ impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RI } } +impl<LeftPublic: PublicKeyBound, RightPublic: PublicKeyBound, const LEFT_PLUS_RIGHT_LEN: usize> PassBy for Public<LeftPublic, RightPublic, LEFT_PLUS_RIGHT_LEN> { + type PassBy = pass_by::Inner<Self, [u8; LEFT_PLUS_RIGHT_LEN]>; +} + + #[cfg(feature = "full_crypto")] impl< LeftPair: TraitPair, @@ -369,7 +374,7 @@ impl<T: sp_std::hash::Hash + for<'a> TryFrom<&'a [u8]> + AsRef<[u8]> + ByteArray } /// A pair of signatures of different types -#[derive(Encode, MaxEncodedLen, TypeInfo, PartialEq, Eq)] +#[derive(Clone, Encode, MaxEncodedLen, TypeInfo, PartialEq, Eq)] #[scale_info(skip_type_params(LeftSignature, RightSignature))] pub struct Signature< LeftSignature: SignatureBound, @@ -666,7 +671,7 @@ where mod test { use super::*; use crate::crypto::DEV_PHRASE; - use ecdsa_n_bls377::{Pair, Signature}; + use ecdsa_bls377::{Pair, Signature}; #[test] fn default_phrase_should_be_used() { diff --git a/substrate/primitives/core/src/testing.rs b/substrate/primitives/core/src/testing.rs index 25f5f9012c996..5a84beac7f7f2 100644 --- a/substrate/primitives/core/src/testing.rs +++ b/substrate/primitives/core/src/testing.rs @@ -31,6 +31,8 @@ pub const BANDERSNATCH: KeyTypeId = KeyTypeId(*b"band"); pub const BLS377: KeyTypeId = KeyTypeId(*b"bls7"); /// Key type for generic BLS12-381 key. pub const BLS381: KeyTypeId = KeyTypeId(*b"bls8"); +/// Key type for (ECDSA, BLS12-377) key pair +pub const ECDSA_BLS377: KeyTypeId = KeyTypeId(*b"ecb7"); /// Macro for exporting functions from wasm in with the expected signature for using it with the /// wasm executor. This is useful for tests where you need to call a function in wasm. diff --git a/substrate/primitives/io/src/lib.rs b/substrate/primitives/io/src/lib.rs index ec098a155c9c5..2730c152c5159 100644 --- a/substrate/primitives/io/src/lib.rs +++ b/substrate/primitives/io/src/lib.rs @@ -106,7 +106,7 @@ use sp_core::{ }; #[cfg(feature = "bls-experimental")] -use sp_core::bls377; +use sp_core::{bls377, ecdsa_bls377}; #[cfg(feature = "std")] use sp_trie::{LayoutV0, LayoutV1, TrieConfiguration}; @@ -1192,7 +1192,8 @@ pub trait Crypto { Ok(pubkey.serialize()) } - /// Generate an `bls12-377` key for the given key type using an optional `seed` and + + /// Generate an `bls12-377` key for the given key type using an optional `seed` and /// store it in the keystore. /// /// The `seed` needs to be a valid utf8. @@ -1207,6 +1208,21 @@ pub trait Crypto { .expect("`bls377_generate` failed") } + // Generate an pair of `(ecdsa,bls12-377)` key for the given key type using an optional `seed` and + /// store it in the keystore. + /// + /// The `seed` needs to be a valid utf8. + /// + /// Returns the public key. + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_generate(&mut self, id: KeyTypeId, seed: Option<Vec<u8>>) -> ecdsa_bls377::Public { + let seed = seed.as_ref().map(|s| std::str::from_utf8(s).expect("Seed is valid utf8!")); + self.extension::<KeystoreExt>() + .expect("No `keystore` associated for the current context!") + .ecdsa_bls377_generate_new(id, seed) + .expect("`ecdsa_bls377_generate` failed") + } + /// Generate a `bandersnatch` key pair for the given key type using an optional /// `seed` and store it in the keystore. /// diff --git a/substrate/primitives/keystore/src/lib.rs b/substrate/primitives/keystore/src/lib.rs index 035af7099a6f8..926abb2258672 100644 --- a/substrate/primitives/keystore/src/lib.rs +++ b/substrate/primitives/keystore/src/lib.rs @@ -23,7 +23,7 @@ pub mod testing; #[cfg(feature = "bandersnatch-experimental")] use sp_core::bandersnatch; #[cfg(feature = "bls-experimental")] -use sp_core::{bls377, bls381}; +use sp_core::{bls377, bls381, ecdsa_bls377}; use sp_core::{ crypto::{ByteArray, CryptoTypeId, KeyTypeId}, ecdsa, ed25519, sr25519, @@ -270,6 +270,10 @@ pub trait Keystore: Send + Sync { #[cfg(feature = "bls-experimental")] fn bls377_public_keys(&self, id: KeyTypeId) -> Vec<bls377::Public>; + /// Returns all (ecdsa,bls12-377) paired public keys for the given key type. + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_public_keys(&self, id: KeyTypeId) -> Vec<ecdsa_bls377::Public>; + /// Generate a new bls381 key pair for the given key type and an optional seed. /// /// Returns an `bls381::Public` key of the generated key pair or an `Err` if @@ -292,6 +296,18 @@ pub trait Keystore: Send + Sync { seed: Option<&str>, ) -> Result<bls377::Public, Error>; + + /// Generate a new (ecdsa,bls377) key pair for the given key type and an optional seed. + /// + /// Returns an `ecdsa_bls377::Public` key of the generated key pair or an `Err` if + /// something failed during key generation. + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_generate_new( + &self, + key_type: KeyTypeId, + seed: Option<&str>, + ) -> Result<ecdsa_bls377::Public, Error>; + /// Generate a bls381 signature for a given message. /// /// Receives [`KeyTypeId`] and a [`bls381::Public`] key to be able to map @@ -324,6 +340,22 @@ pub trait Keystore: Send + Sync { msg: &[u8], ) -> Result<Option<bls377::Signature>, Error>; + /// Generate a (ecdsa, bls377) signature pair for a given message. + /// + /// Receives [`KeyTypeId`] and a [`ecdsa_bls377::Public`] key to be able to map + /// them to a private key that exists in the keystore. + /// + /// Returns an [`ecdsa_bls377::Signature`] or `None` in case the given `key_type` + /// and `public` combination doesn't exist in the keystore. + /// An `Err` will be returned if generating the signature itself failed. + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_sign( + &self, + key_type: KeyTypeId, + public: &ecdsa_bls377::Public, + msg: &[u8], + ) -> Result<Option<ecdsa_bls377::Signature>, Error>; + /// Insert a new secret key. fn insert(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()>; @@ -348,7 +380,8 @@ pub trait Keystore: Send + Sync { /// - ecdsa /// - bandersnatch /// - bls381 - /// - bls377 + /// - bls377 + /// - (ecdsa,bls377) paired keys /// /// To support more schemes you can overwrite this method. /// @@ -398,6 +431,13 @@ pub trait Keystore: Send + Sync { .map_err(|_| Error::ValidationError("Invalid public key format".into()))?; self.bls377_sign(id, &public, msg)?.map(|s| s.encode()) }, + #[cfg(feature = "bls-experimental")] + ecdsa_bls377::CRYPTO_ID => { + let public = ecdsa_bls377::Public::from_slice(public) + .map_err(|_| Error::ValidationError("Invalid public key format".into()))?; + self.ecdsa_bls377_sign(id, &public, msg)?.map(|s| s.encode()) + }, + _ => return Err(Error::KeyNotSupported(id)), }; Ok(signature) @@ -560,6 +600,11 @@ impl<T: Keystore + ?Sized> Keystore for Arc<T> { (**self).bls377_public_keys(id) } + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_public_keys(&self, id: KeyTypeId) -> Vec<ecdsa_bls377::Public> { + (**self).ecdsa_bls377_public_keys(id) + } + #[cfg(feature = "bls-experimental")] fn bls381_generate_new( &self, @@ -578,7 +623,17 @@ impl<T: Keystore + ?Sized> Keystore for Arc<T> { (**self).bls377_generate_new(key_type, seed) } - #[cfg(feature = "bls-experimental")] + + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_generate_new( + &self, + key_type: KeyTypeId, + seed: Option<&str>, + ) -> Result<ecdsa_bls377::Public, Error> { + (**self).ecdsa_bls377_generate_new(key_type, seed) + } + + #[cfg(feature = "bls-experimental")] fn bls381_sign( &self, key_type: KeyTypeId, @@ -598,6 +653,16 @@ impl<T: Keystore + ?Sized> Keystore for Arc<T> { (**self).bls377_sign(key_type, public, msg) } + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_sign( + &self, + key_type: KeyTypeId, + public: &ecdsa_bls377::Public, + msg: &[u8], + ) -> Result<Option<ecdsa_bls377::Signature>, Error> { + (**self).ecdsa_bls377_sign(key_type, public, msg) + } + fn insert(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()> { (**self).insert(key_type, suri, public) } diff --git a/substrate/primitives/keystore/src/testing.rs b/substrate/primitives/keystore/src/testing.rs index efa35fd24bf46..feb755fe578b0 100644 --- a/substrate/primitives/keystore/src/testing.rs +++ b/substrate/primitives/keystore/src/testing.rs @@ -22,7 +22,7 @@ use crate::{Error, Keystore, KeystorePtr}; #[cfg(feature = "bandersnatch-experimental")] use sp_core::bandersnatch; #[cfg(feature = "bls-experimental")] -use sp_core::{bls377, bls381}; +use sp_core::{bls377, bls381, ecdsa_bls377}; use sp_core::{ crypto::{ByteArray, KeyTypeId, Pair, VrfSecret}, ecdsa, ed25519, sr25519, @@ -322,6 +322,30 @@ impl Keystore for MemoryKeystore { self.sign::<bls377::Pair>(key_type, public, msg) } + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_public_keys(&self, key_type: KeyTypeId) -> Vec<ecdsa_bls377::Public> { + self.public_keys::<ecdsa_bls377::Pair>(key_type) + } + + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_generate_new( + &self, + key_type: KeyTypeId, + seed: Option<&str>, + ) -> Result<ecdsa_bls377::Public, Error> { + self.generate_new::<ecdsa_bls377::Pair>(key_type, seed) + } + + #[cfg(feature = "bls-experimental")] + fn ecdsa_bls377_sign( + &self, + key_type: KeyTypeId, + public: &ecdsa_bls377::Public, + msg: &[u8], + ) -> Result<Option<ecdsa_bls377::Signature>, Error> { + self.sign::<ecdsa_bls377::Pair>(key_type, public, msg) + } + fn insert(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()> { self.keys .write() From 067decec3cff6ea15cf52cc1785f40b3cbf0d9dc Mon Sep 17 00:00:00 2001 From: Skalman <skalman@riseup.net> Date: Fri, 6 Oct 2023 12:16:33 -0400 Subject: [PATCH 25/30] cargo fmt --- .../primitives/application-crypto/src/lib.rs | 2 +- .../primitives/consensus/beefy/src/lib.rs | 5 ++--- substrate/primitives/keystore/src/lib.rs | 22 +++++++++---------- substrate/primitives/keystore/src/testing.rs | 2 +- 4 files changed, 14 insertions(+), 17 deletions(-) diff --git a/substrate/primitives/application-crypto/src/lib.rs b/substrate/primitives/application-crypto/src/lib.rs index 9fab4ccbdc09b..686b486f33530 100644 --- a/substrate/primitives/application-crypto/src/lib.rs +++ b/substrate/primitives/application-crypto/src/lib.rs @@ -49,9 +49,9 @@ pub mod bandersnatch; pub mod bls377; #[cfg(feature = "bls-experimental")] pub mod bls381; +pub mod ecdsa; #[cfg(feature = "bls-experimental")] pub mod ecdsa_bls377; -pub mod ecdsa; pub mod ed25519; pub mod sr25519; mod traits; diff --git a/substrate/primitives/consensus/beefy/src/lib.rs b/substrate/primitives/consensus/beefy/src/lib.rs index 4a842fa42acd6..d4f3213740427 100644 --- a/substrate/primitives/consensus/beefy/src/lib.rs +++ b/substrate/primitives/consensus/beefy/src/lib.rs @@ -155,7 +155,7 @@ pub mod bls_crypto { pub mod ecdsa_bls_crypto { use super::{BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE as BEEFY_KEY_TYPE}; use sp_application_crypto::{app_crypto, ecdsa_bls377}; - use sp_core::{ecdsa_bls377::Pair as EcdsaBlsPair, crypto::Wraps, Pair as _}; + use sp_core::{crypto::Wraps, ecdsa_bls377::Pair as EcdsaBlsPair, Pair as _}; app_crypto!(ecdsa_bls377, BEEFY_KEY_TYPE); /// Identity of a BEEFY authority using BLS as its crypto. @@ -498,7 +498,7 @@ mod tests { assert!(!BeefyAuthorityId::<Keccak256>::verify(&other_pair.public(), &signature, msg,)); } - #[test] + #[test] #[cfg(feature = "bls-experimental")] fn ecdsa_bls_beefy_verify_works() { let msg = &b"test-message"[..]; @@ -513,5 +513,4 @@ mod tests { let (other_pair, _) = ecdsa_bls_crypto::Pair::generate(); assert!(!BeefyAuthorityId::<Keccak256>::verify(&other_pair.public(), &signature, msg,)); } - } diff --git a/substrate/primitives/keystore/src/lib.rs b/substrate/primitives/keystore/src/lib.rs index 926abb2258672..9fbb336f195c9 100644 --- a/substrate/primitives/keystore/src/lib.rs +++ b/substrate/primitives/keystore/src/lib.rs @@ -270,7 +270,7 @@ pub trait Keystore: Send + Sync { #[cfg(feature = "bls-experimental")] fn bls377_public_keys(&self, id: KeyTypeId) -> Vec<bls377::Public>; - /// Returns all (ecdsa,bls12-377) paired public keys for the given key type. + /// Returns all (ecdsa,bls12-377) paired public keys for the given key type. #[cfg(feature = "bls-experimental")] fn ecdsa_bls377_public_keys(&self, id: KeyTypeId) -> Vec<ecdsa_bls377::Public>; @@ -296,7 +296,6 @@ pub trait Keystore: Send + Sync { seed: Option<&str>, ) -> Result<bls377::Public, Error>; - /// Generate a new (ecdsa,bls377) key pair for the given key type and an optional seed. /// /// Returns an `ecdsa_bls377::Public` key of the generated key pair or an `Err` if @@ -340,7 +339,7 @@ pub trait Keystore: Send + Sync { msg: &[u8], ) -> Result<Option<bls377::Signature>, Error>; - /// Generate a (ecdsa, bls377) signature pair for a given message. + /// Generate a (ecdsa, bls377) signature pair for a given message. /// /// Receives [`KeyTypeId`] and a [`ecdsa_bls377::Public`] key to be able to map /// them to a private key that exists in the keystore. @@ -348,7 +347,7 @@ pub trait Keystore: Send + Sync { /// Returns an [`ecdsa_bls377::Signature`] or `None` in case the given `key_type` /// and `public` combination doesn't exist in the keystore. /// An `Err` will be returned if generating the signature itself failed. - #[cfg(feature = "bls-experimental")] + #[cfg(feature = "bls-experimental")] fn ecdsa_bls377_sign( &self, key_type: KeyTypeId, @@ -380,8 +379,8 @@ pub trait Keystore: Send + Sync { /// - ecdsa /// - bandersnatch /// - bls381 - /// - bls377 - /// - (ecdsa,bls377) paired keys + /// - bls377 + /// - (ecdsa,bls377) paired keys /// /// To support more schemes you can overwrite this method. /// @@ -437,7 +436,7 @@ pub trait Keystore: Send + Sync { .map_err(|_| Error::ValidationError("Invalid public key format".into()))?; self.ecdsa_bls377_sign(id, &public, msg)?.map(|s| s.encode()) }, - + _ => return Err(Error::KeyNotSupported(id)), }; Ok(signature) @@ -623,8 +622,7 @@ impl<T: Keystore + ?Sized> Keystore for Arc<T> { (**self).bls377_generate_new(key_type, seed) } - - #[cfg(feature = "bls-experimental")] + #[cfg(feature = "bls-experimental")] fn ecdsa_bls377_generate_new( &self, key_type: KeyTypeId, @@ -633,7 +631,7 @@ impl<T: Keystore + ?Sized> Keystore for Arc<T> { (**self).ecdsa_bls377_generate_new(key_type, seed) } - #[cfg(feature = "bls-experimental")] + #[cfg(feature = "bls-experimental")] fn bls381_sign( &self, key_type: KeyTypeId, @@ -653,7 +651,7 @@ impl<T: Keystore + ?Sized> Keystore for Arc<T> { (**self).bls377_sign(key_type, public, msg) } - #[cfg(feature = "bls-experimental")] + #[cfg(feature = "bls-experimental")] fn ecdsa_bls377_sign( &self, key_type: KeyTypeId, @@ -661,7 +659,7 @@ impl<T: Keystore + ?Sized> Keystore for Arc<T> { msg: &[u8], ) -> Result<Option<ecdsa_bls377::Signature>, Error> { (**self).ecdsa_bls377_sign(key_type, public, msg) - } + } fn insert(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()> { (**self).insert(key_type, suri, public) diff --git a/substrate/primitives/keystore/src/testing.rs b/substrate/primitives/keystore/src/testing.rs index feb755fe578b0..7f5dfd9faa713 100644 --- a/substrate/primitives/keystore/src/testing.rs +++ b/substrate/primitives/keystore/src/testing.rs @@ -345,7 +345,7 @@ impl Keystore for MemoryKeystore { ) -> Result<Option<ecdsa_bls377::Signature>, Error> { self.sign::<ecdsa_bls377::Pair>(key_type, public, msg) } - + fn insert(&self, key_type: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()> { self.keys .write() From 652990e93e9397faf0563b36c6968f6be5652bf7 Mon Sep 17 00:00:00 2001 From: Skalman <skalman@riseup.net> Date: Tue, 17 Oct 2023 12:44:23 -0400 Subject: [PATCH 26/30] `cargo fmt` --- substrate/primitives/core/src/bls.rs | 6 +++--- substrate/primitives/core/src/ecdsa.rs | 2 +- substrate/primitives/core/src/lib.rs | 2 +- substrate/primitives/io/src/lib.rs | 12 ++++++++---- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/substrate/primitives/core/src/bls.rs b/substrate/primitives/core/src/bls.rs index f6a4fb12272da..8ce6eb166f868 100644 --- a/substrate/primitives/core/src/bls.rs +++ b/substrate/primitives/core/src/bls.rs @@ -206,7 +206,7 @@ impl<T> TryFrom<&[u8]> for Public<T> { fn try_from(data: &[u8]) -> Result<Self, Self::Error> { if data.len() != PUBLIC_KEY_SERIALIZED_SIZE { - return Err(()); + return Err(()) } let mut r = [0u8; PUBLIC_KEY_SERIALIZED_SIZE]; r.copy_from_slice(data); @@ -332,7 +332,7 @@ impl<T> TryFrom<&[u8]> for Signature<T> { fn try_from(data: &[u8]) -> Result<Self, Self::Error> { if data.len() != SIGNATURE_SERIALIZED_SIZE { - return Err(()); + return Err(()) } let mut inner = [0u8; SIGNATURE_SERIALIZED_SIZE]; inner.copy_from_slice(data); @@ -442,7 +442,7 @@ impl<T: BlsBound> TraitPair for Pair<T> { fn from_seed_slice(seed_slice: &[u8]) -> Result<Self, SecretStringError> { if seed_slice.len() != SECRET_KEY_SERIALIZED_SIZE { - return Err(SecretStringError::InvalidSeedLength); + return Err(SecretStringError::InvalidSeedLength) } let secret = w3f_bls::SecretKey::from_seed(seed_slice); let public = secret.into_public(); diff --git a/substrate/primitives/core/src/ecdsa.rs b/substrate/primitives/core/src/ecdsa.rs index e3d9feb2c5482..603fa515a30e8 100644 --- a/substrate/primitives/core/src/ecdsa.rs +++ b/substrate/primitives/core/src/ecdsa.rs @@ -139,7 +139,7 @@ impl TryFrom<&[u8]> for Public { fn try_from(data: &[u8]) -> Result<Self, Self::Error> { if data.len() != Self::LEN { - return Err(()); + return Err(()) } let mut r = [0u8; Self::LEN]; r.copy_from_slice(data); diff --git a/substrate/primitives/core/src/lib.rs b/substrate/primitives/core/src/lib.rs index 131d4739a1b0b..ec0641c54668b 100644 --- a/substrate/primitives/core/src/lib.rs +++ b/substrate/primitives/core/src/lib.rs @@ -59,7 +59,6 @@ pub use paste; pub mod bandersnatch; #[cfg(feature = "bls-experimental")] pub mod bls; -pub mod paired_crypto; pub mod defer; pub mod ecdsa; pub mod ed25519; @@ -67,6 +66,7 @@ pub mod hash; #[cfg(feature = "std")] mod hasher; pub mod offchain; +pub mod paired_crypto; pub mod sr25519; pub mod testing; #[cfg(feature = "std")] diff --git a/substrate/primitives/io/src/lib.rs b/substrate/primitives/io/src/lib.rs index 2730c152c5159..2912dca9527ac 100644 --- a/substrate/primitives/io/src/lib.rs +++ b/substrate/primitives/io/src/lib.rs @@ -1192,8 +1192,7 @@ pub trait Crypto { Ok(pubkey.serialize()) } - - /// Generate an `bls12-377` key for the given key type using an optional `seed` and + /// Generate an `bls12-377` key for the given key type using an optional `seed` and /// store it in the keystore. /// /// The `seed` needs to be a valid utf8. @@ -1208,14 +1207,19 @@ pub trait Crypto { .expect("`bls377_generate` failed") } - // Generate an pair of `(ecdsa,bls12-377)` key for the given key type using an optional `seed` and + // Generate an pair of `(ecdsa,bls12-377)` key for the given key type using an optional `seed` + // and /// store it in the keystore. /// /// The `seed` needs to be a valid utf8. /// /// Returns the public key. #[cfg(feature = "bls-experimental")] - fn ecdsa_bls377_generate(&mut self, id: KeyTypeId, seed: Option<Vec<u8>>) -> ecdsa_bls377::Public { + fn ecdsa_bls377_generate( + &mut self, + id: KeyTypeId, + seed: Option<Vec<u8>>, + ) -> ecdsa_bls377::Public { let seed = seed.as_ref().map(|s| std::str::from_utf8(s).expect("Seed is valid utf8!")); self.extension::<KeystoreExt>() .expect("No `keystore` associated for the current context!") From 388ed145d78929e110a51364346ecb8aebb16f2a Mon Sep 17 00:00:00 2001 From: Davide Galassi <davxy@datawok.net> Date: Thu, 19 Oct 2023 09:15:12 +0200 Subject: [PATCH 27/30] Nitpicks --- .../application-crypto/src/ecdsa_bls377.rs | 3 ++- .../primitives/consensus/beefy/src/lib.rs | 27 ++++++++++--------- substrate/primitives/io/src/lib.rs | 3 +-- substrate/primitives/keystore/src/lib.rs | 2 +- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/substrate/primitives/application-crypto/src/ecdsa_bls377.rs b/substrate/primitives/application-crypto/src/ecdsa_bls377.rs index ae4214c9803d0..70940587cedaf 100644 --- a/substrate/primitives/application-crypto/src/ecdsa_bls377.rs +++ b/substrate/primitives/application-crypto/src/ecdsa_bls377.rs @@ -15,7 +15,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! BLS12-377 crypto applications. +//! ECDSA and BLS12-377 paired crypto applications. + use crate::{KeyTypeId, RuntimePublic}; pub use sp_core::paired_crypto::ecdsa_bls377::*; diff --git a/substrate/primitives/consensus/beefy/src/lib.rs b/substrate/primitives/consensus/beefy/src/lib.rs index d4f3213740427..5bdf8ce010a10 100644 --- a/substrate/primitives/consensus/beefy/src/lib.rs +++ b/substrate/primitives/consensus/beefy/src/lib.rs @@ -74,10 +74,11 @@ pub trait BeefyAuthorityId<MsgHash: Hash>: RuntimeAppPublic { /// Your code should use the above types as concrete types for all crypto related /// functionality. pub mod ecdsa_crypto { - use super::{BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE as BEEFY_KEY_TYPE}; + use super::{BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE}; use sp_application_crypto::{app_crypto, ecdsa}; use sp_core::crypto::Wraps; - app_crypto!(ecdsa, BEEFY_KEY_TYPE); + + app_crypto!(ecdsa, KEY_TYPE); /// Identity of a BEEFY authority using ECDSA as its crypto. pub type AuthorityId = Public; @@ -115,10 +116,11 @@ pub mod ecdsa_crypto { #[cfg(feature = "bls-experimental")] pub mod bls_crypto { - use super::{BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE as BEEFY_KEY_TYPE}; + use super::{BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE}; use sp_application_crypto::{app_crypto, bls377}; use sp_core::{bls377::Pair as BlsPair, crypto::Wraps, Pair as _}; - app_crypto!(bls377, BEEFY_KEY_TYPE); + + app_crypto!(bls377, KEY_TYPE); /// Identity of a BEEFY authority using BLS as its crypto. pub type AuthorityId = Public; @@ -144,24 +146,25 @@ pub mod bls_crypto { /// BEEFY cryptographic types for (ECDSA,BLS) crypto pair /// /// This module basically introduces four crypto types: -/// - `bls_crypto::Pair` -/// - `bls_crypto::Public` -/// - `bls_crypto::Signature` -/// - `bls_crypto::AuthorityId` +/// - `ecdsa_bls_crypto::Pair` +/// - `ecdsa_bls_crypto::Public` +/// - `ecdsa_bls_crypto::Signature` +/// - `ecdsa_bls_crypto::AuthorityId` /// /// Your code should use the above types as concrete types for all crypto related /// functionality. #[cfg(feature = "bls-experimental")] pub mod ecdsa_bls_crypto { - use super::{BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE as BEEFY_KEY_TYPE}; + use super::{BeefyAuthorityId, Hash, RuntimeAppPublic, KEY_TYPE}; use sp_application_crypto::{app_crypto, ecdsa_bls377}; use sp_core::{crypto::Wraps, ecdsa_bls377::Pair as EcdsaBlsPair, Pair as _}; - app_crypto!(ecdsa_bls377, BEEFY_KEY_TYPE); - /// Identity of a BEEFY authority using BLS as its crypto. + app_crypto!(ecdsa_bls377, KEY_TYPE); + + /// Identity of a BEEFY authority using (ECDSA,BLS) as its crypto. pub type AuthorityId = Public; - /// Signature for a BEEFY authority using BLS as its crypto. + /// Signature for a BEEFY authority using (ECDSA,BLS) as its crypto. pub type AuthoritySignature = Signature; impl<MsgHash: Hash> BeefyAuthorityId<MsgHash> for AuthorityId diff --git a/substrate/primitives/io/src/lib.rs b/substrate/primitives/io/src/lib.rs index 2912dca9527ac..dde8eff17159c 100644 --- a/substrate/primitives/io/src/lib.rs +++ b/substrate/primitives/io/src/lib.rs @@ -1207,8 +1207,7 @@ pub trait Crypto { .expect("`bls377_generate` failed") } - // Generate an pair of `(ecdsa,bls12-377)` key for the given key type using an optional `seed` - // and + /// Generate an `(ecdsa, bls12-377)` key for the given key type using an optional `seed` and /// store it in the keystore. /// /// The `seed` needs to be a valid utf8. diff --git a/substrate/primitives/keystore/src/lib.rs b/substrate/primitives/keystore/src/lib.rs index 9fbb336f195c9..e415080779cf4 100644 --- a/substrate/primitives/keystore/src/lib.rs +++ b/substrate/primitives/keystore/src/lib.rs @@ -339,7 +339,7 @@ pub trait Keystore: Send + Sync { msg: &[u8], ) -> Result<Option<bls377::Signature>, Error>; - /// Generate a (ecdsa, bls377) signature pair for a given message. + /// Generate a (ecdsa,bls377) signature pair for a given message. /// /// Receives [`KeyTypeId`] and a [`ecdsa_bls377::Public`] key to be able to map /// them to a private key that exists in the keystore. From 9f07bd5fbe2034fae71d03de7e3d7dcb4b4bffd7 Mon Sep 17 00:00:00 2001 From: Skalman <skalman@riseup.net> Date: Fri, 20 Oct 2023 04:35:25 -0400 Subject: [PATCH 28/30] implement ecdsa_bls377 `Keystore` functions for `LocalKeystore`. --- substrate/client/keystore/src/local.rs | 27 +++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/substrate/client/keystore/src/local.rs b/substrate/client/keystore/src/local.rs index c77f023e0f0af..8089dbba03529 100644 --- a/substrate/client/keystore/src/local.rs +++ b/substrate/client/keystore/src/local.rs @@ -37,7 +37,7 @@ use sp_core::bandersnatch; } sp_keystore::bls_experimental_enabled! { -use sp_core::{bls377, bls381}; +use sp_core::{bls377, bls381, ecdsa_bls377}; } use crate::{Error, Result}; @@ -366,6 +366,31 @@ impl Keystore for LocalKeystore { ) -> std::result::Result<Option<bls377::Signature>, TraitError> { self.sign::<bls377::Pair>(key_type, public, msg) } + + fn ecdsa_bls377_public_keys(&self, key_type: KeyTypeId) -> Vec<ecdsa_bls377::Public> { + self.public_keys::<ecdsa_bls377::Pair>(key_type) + } + + /// Generate a new pair of paired-keys compatible with the '(ecdsa,bls377)' signature scheme. + /// + /// If `[seed]` is `Some` then the key will be ephemeral and stored in memory. + fn ecdsa_bls377_generate_new( + &self, + key_type: KeyTypeId, + seed: Option<&str>, + ) -> std::result::Result<ecdsa_bls377::Public, TraitError> { + self.generate_new::<ecdsa_bls377::Pair>(key_type, seed) + } + + fn ecdsa_bls377_sign( + &self, + key_type: KeyTypeId, + public: &ecdsa_bls377::Public, + msg: &[u8], + ) -> std::result::Result<Option<ecdsa_bls377::Signature>, TraitError> { + self.sign::<ecdsa_bls377::Pair>(key_type, public, msg) + } + } } From fdd1bdf841324822f134ab575b03b1e02dac3f4e Mon Sep 17 00:00:00 2001 From: Robert Hambrock <roberthambrock@gmail.com> Date: Tue, 24 Oct 2023 15:06:54 +0200 Subject: [PATCH 29/30] nitpick tuple consistency Suggested-by: Davide Galassi <davxy@datawok.net> --- substrate/primitives/core/src/paired_crypto.rs | 8 ++++---- substrate/primitives/core/src/testing.rs | 2 +- substrate/primitives/io/src/lib.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/substrate/primitives/core/src/paired_crypto.rs b/substrate/primitives/core/src/paired_crypto.rs index 28e396f300c00..a97b657e7578f 100644 --- a/substrate/primitives/core/src/paired_crypto.rs +++ b/substrate/primitives/core/src/paired_crypto.rs @@ -49,12 +49,12 @@ pub mod ecdsa_bls377 { const SIGNATURE_LEN: usize = ecdsa::SIGNATURE_SERIALIZED_SIZE + bls377::SIGNATURE_SERIALIZED_SIZE; - /// (ECDSA, BLS12-377) key-pair pair. + /// (ECDSA,BLS12-377) key-pair pair. #[cfg(feature = "full_crypto")] pub type Pair = super::Pair<ecdsa::Pair, bls377::Pair, PUBLIC_KEY_LEN, SIGNATURE_LEN>; - /// (ECDSA, BLS12-377) public key pair. + /// (ECDSA,BLS12-377) public key pair. pub type Public = super::Public<PUBLIC_KEY_LEN>; - /// (ECDSA, BLS12-377) signature pair. + /// (ECDSA,BLS12-377) signature pair. pub type Signature = super::Signature<SIGNATURE_LEN>; impl super::CryptoType for Public { @@ -451,7 +451,7 @@ where } } -// Test set exercising the (ECDSA, BLS12-377) implementation +// Test set exercising the (ECDSA,BLS12-377) implementation #[cfg(all(test, feature = "bls-experimental"))] mod test { use super::*; diff --git a/substrate/primitives/core/src/testing.rs b/substrate/primitives/core/src/testing.rs index 5a84beac7f7f2..947dcc387fc79 100644 --- a/substrate/primitives/core/src/testing.rs +++ b/substrate/primitives/core/src/testing.rs @@ -31,7 +31,7 @@ pub const BANDERSNATCH: KeyTypeId = KeyTypeId(*b"band"); pub const BLS377: KeyTypeId = KeyTypeId(*b"bls7"); /// Key type for generic BLS12-381 key. pub const BLS381: KeyTypeId = KeyTypeId(*b"bls8"); -/// Key type for (ECDSA, BLS12-377) key pair +/// Key type for (ECDSA,BLS12-377) key pair pub const ECDSA_BLS377: KeyTypeId = KeyTypeId(*b"ecb7"); /// Macro for exporting functions from wasm in with the expected signature for using it with the diff --git a/substrate/primitives/io/src/lib.rs b/substrate/primitives/io/src/lib.rs index dde8eff17159c..c4182d6ab3a00 100644 --- a/substrate/primitives/io/src/lib.rs +++ b/substrate/primitives/io/src/lib.rs @@ -1207,7 +1207,7 @@ pub trait Crypto { .expect("`bls377_generate` failed") } - /// Generate an `(ecdsa, bls12-377)` key for the given key type using an optional `seed` and + /// Generate an `(ecdsa,bls12-377)` key for the given key type using an optional `seed` and /// store it in the keystore. /// /// The `seed` needs to be a valid utf8. From 305a003fd04fd8c1637b8605ed345aef425f0169 Mon Sep 17 00:00:00 2001 From: Robert Hambrock <roberthambrock@gmail.com> Date: Tue, 24 Oct 2023 16:01:14 +0200 Subject: [PATCH 30/30] reuse `Ord` impl for `PartialOrd` impl of `Public` --- substrate/primitives/core/src/bls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/primitives/core/src/bls.rs b/substrate/primitives/core/src/bls.rs index 8ce6eb166f868..e519ba1806c41 100644 --- a/substrate/primitives/core/src/bls.rs +++ b/substrate/primitives/core/src/bls.rs @@ -134,7 +134,7 @@ impl<T> Eq for Public<T> {} impl<T> PartialOrd for Public<T> { fn partial_cmp(&self, other: &Self) -> Option<sp_std::cmp::Ordering> { - self.inner.partial_cmp(&other.inner) + Some(self.cmp(other)) } }