Implement crypto byte array newtypes in term of a shared type (#3684)

Introduces `CryptoBytes` type defined as:

```rust
pub struct CryptoBytes<const N: usize, Tag = ()>(pub [u8; N], PhantomData<fn() -> Tag>);
```

The type implements a bunch of methods and traits which are typically
expected from a byte array newtype
(NOTE: some of the methods and trait implementations IMO are a bit
redundant, but I decided to maintain them all to not change too much
stuff in this PR)

It also introduces two (generic) typical consumers of `CryptoBytes`:
`PublicBytes` and `SignatureBytes`.

```rust
pub struct PublicTag;
pub PublicBytes<const N: usize, CryptoTag> = CryptoBytes<N, (PublicTag, CryptoTag)>;

pub struct SignatureTag;
pub SignatureBytes<const N: usize, CryptoTag> = CryptoBytes<N, (SignatureTag, CryptoTag)>;
```

Both of them use a tag to differentiate the two types at a higher level.
Downstream specializations will further specialize using a dedicated
crypto tag. For example in ECDSA:


```rust
pub struct EcdsaTag;

pub type Public = PublicBytes<PUBLIC_KEY_SERIALIZED_SIZE, EcdsaTag>;
pub type Signature = PublicBytes<PUBLIC_KEY_SERIALIZED_SIZE, EcdsaTag>;
```

Overall we have a cleaner and most importantly **consistent** code for
all the types involved

All these details are opaque to the end user which can use `Public` and
`Signature` for the cryptos as before
This commit is contained in:
Davide Galassi
2024-03-19 16:47:42 +01:00
committed by GitHub
parent 5fd72a1f5e
commit 1e9fd23776
29 changed files with 492 additions and 1163 deletions
+3 -3
View File
@@ -144,7 +144,7 @@ impl RelayChainInterface for DummyRelayChainInterface {
persisted_validation_data_hash: PHash::random(),
pov_hash: PHash::random(),
erasure_root: PHash::random(),
signature: sp_core::sr25519::Signature([0u8; 64]).into(),
signature: sp_core::sr25519::Signature::default().into(),
validation_code_hash: ValidationCodeHash::from(PHash::random()),
},
commitments: CandidateCommitments {
@@ -325,7 +325,7 @@ async fn make_gossip_message_and_header(
persisted_validation_data_hash: PHash::random(),
pov_hash: PHash::random(),
erasure_root: PHash::random(),
signature: sp_core::sr25519::Signature([0u8; 64]).into(),
signature: sp_core::sr25519::Signature::default().into(),
para_head: polkadot_parachain_primitives::primitives::HeadData(header.encode()).hash(),
validation_code_hash: ValidationCodeHash::from(PHash::random()),
},
@@ -516,7 +516,7 @@ async fn check_statement_seconded() {
persisted_validation_data_hash: PHash::random(),
pov_hash: PHash::random(),
erasure_root: PHash::random(),
signature: sp_core::sr25519::Signature([0u8; 64]).into(),
signature: sp_core::sr25519::Signature::default().into(),
validation_code_hash: ValidationCodeHash::from(PHash::random()),
},
},
@@ -190,12 +190,7 @@ fn construct_extrinsic(
);
let payload = SignedPayload::new(call.clone(), extra.clone()).unwrap();
let signature = payload.using_encoded(|e| sender.sign(e));
UncheckedExtrinsic::new_signed(
call,
account_id.into(),
Signature::Sr25519(signature.clone()),
extra,
)
UncheckedExtrinsic::new_signed(call, account_id.into(), Signature::Sr25519(signature), extra)
}
fn construct_and_apply_extrinsic(
@@ -67,12 +67,7 @@ fn construct_extrinsic(
);
let payload = SignedPayload::new(call.clone(), extra.clone()).unwrap();
let signature = payload.using_encoded(|e| sender.sign(e));
UncheckedExtrinsic::new_signed(
call,
account_id.into(),
Signature::Sr25519(signature.clone()),
extra,
)
UncheckedExtrinsic::new_signed(call, account_id.into(), Signature::Sr25519(signature), extra)
}
fn construct_and_apply_extrinsic(
@@ -81,12 +81,7 @@ fn construct_extrinsic(
);
let payload = SignedPayload::new(call.clone(), extra.clone()).unwrap();
let signature = payload.using_encoded(|e| sender.sign(e));
UncheckedExtrinsic::new_signed(
call,
account_id.into(),
Signature::Sr25519(signature.clone()),
extra,
)
UncheckedExtrinsic::new_signed(call, account_id.into(), Signature::Sr25519(signature), extra)
}
fn construct_and_apply_extrinsic(
+2 -2
View File
@@ -222,7 +222,7 @@ fn westend_sign_call(
runtime::UncheckedExtrinsic::new_signed(
call,
sp_runtime::AccountId32::from(acc.public()).into(),
polkadot_core_primitives::Signature::Sr25519(signature.clone()),
polkadot_core_primitives::Signature::Sr25519(signature),
extra,
)
.into()
@@ -274,7 +274,7 @@ fn rococo_sign_call(
runtime::UncheckedExtrinsic::new_signed(
call,
sp_runtime::AccountId32::from(acc.public()).into(),
polkadot_core_primitives::Signature::Sr25519(signature.clone()),
polkadot_core_primitives::Signature::Sr25519(signature),
extra,
)
.into()
+1 -1
View File
@@ -410,7 +410,7 @@ pub fn construct_extrinsic(
UncheckedExtrinsic::new_signed(
function.clone(),
polkadot_test_runtime::Address::Id(caller.public().into()),
polkadot_primitives::Signature::Sr25519(signature.clone()),
polkadot_primitives::Signature::Sr25519(signature),
extra.clone(),
)
}
+2 -2
View File
@@ -1953,11 +1953,11 @@ mod tests {
descriptor: CandidateDescriptor {
para_id: 0.into(),
relay_parent: zeros,
collator: CollatorId::from(sr25519::Public::from_raw([0; 32])),
collator: CollatorId::from(sr25519::Public::default()),
persisted_validation_data_hash: zeros,
pov_hash: zeros,
erasure_root: zeros,
signature: CollatorSignature::from(sr25519::Signature([0u8; 64])),
signature: CollatorSignature::from(sr25519::Signature::default()),
para_head: zeros,
validation_code_hash: ValidationCode(vec![1, 2, 3, 4, 5, 6, 7, 8, 9]).hash(),
},
+3 -3
View File
@@ -136,17 +136,17 @@ pub fn dummy_head_data() -> HeadData {
/// Create a meaningless collator id.
pub fn dummy_collator() -> CollatorId {
CollatorId::from(sr25519::Public::from_raw([0; 32]))
CollatorId::from(sr25519::Public::default())
}
/// Create a meaningless validator id.
pub fn dummy_validator() -> ValidatorId {
ValidatorId::from(sr25519::Public::from_raw([0; 32]))
ValidatorId::from(sr25519::Public::default())
}
/// Create a meaningless collator signature.
pub fn dummy_collator_signature() -> CollatorSignature {
CollatorSignature::from(sr25519::Signature([0u8; 64]))
CollatorSignature::from(sr25519::Signature::default())
}
/// Create a meaningless persisted validation data.
+2 -2
View File
@@ -425,8 +425,8 @@ pub mod pallet {
impl<T: Config> Pallet<T> {
fn verify_signature(who: &T::AccountId, signature: &[u8]) -> Result<(), DispatchError> {
// sr25519 always expects a 64 byte signature.
let signature: AnySignature = sr25519::Signature::from_slice(signature)
.ok_or(Error::<T>::InvalidSignature)?
let signature: AnySignature = sr25519::Signature::try_from(signature)
.map_err(|_| Error::<T>::InvalidSignature)?
.into();
// In Polkadot, the AccountId is always the same as the 32 byte public key.
+1 -1
View File
@@ -272,7 +272,7 @@ impl<T: paras_inherent::Config> BenchBuilder<T> {
persisted_validation_data_hash: Default::default(),
pov_hash: Default::default(),
erasure_root: Default::default(),
signature: CollatorSignature::from(sr25519::Signature([42u8; 64])),
signature: CollatorSignature::from(sr25519::Signature::from_raw([42u8; 64])),
para_head: Default::default(),
validation_code_hash: mock_validation_code().hash(),
}
@@ -100,7 +100,7 @@ fn cryptos_are_compatible() {
let sp_core_signature = sp_core_secret.sign(message); // no error expected...
assert!(sp_core::ed25519::Pair::verify(
&sp_core::ed25519::Signature::from_slice(&libp2p_signature).unwrap(),
&sp_core::ed25519::Signature::try_from(libp2p_signature.as_slice()).unwrap(),
message,
&sp_core_public
));
@@ -181,7 +181,7 @@ sp_core::wasm_export_functions! {
sig.copy_from_slice(&input[32..96]);
let msg = b"all ok!";
ed25519_verify(&ed25519::Signature(sig), &msg[..], &ed25519::Public(pubkey))
ed25519_verify(&ed25519::Signature::from(sig), &msg[..], &ed25519::Public::from(pubkey))
}
fn test_sr25519_verify(input: Vec<u8>) -> bool {
@@ -192,7 +192,7 @@ sp_core::wasm_export_functions! {
sig.copy_from_slice(&input[32..96]);
let msg = b"all ok!";
sr25519_verify(&sr25519::Signature(sig), &msg[..], &sr25519::Public(pubkey))
sr25519_verify(&sr25519::Signature::from(sig), &msg[..], &sr25519::Public::from(pubkey))
}
fn test_ordered_trie_root() -> Vec<u8> {
@@ -2226,11 +2226,11 @@ fn reorg_triggers_a_notification_even_for_sources_that_should_not_trigger_notifi
#[test]
fn use_dalek_ext_works() {
fn zero_ed_pub() -> sp_core::ed25519::Public {
sp_core::ed25519::Public([0u8; 32])
sp_core::ed25519::Public::default()
}
fn zero_ed_sig() -> sp_core::ed25519::Signature {
sp_core::ed25519::Signature::from_raw([0u8; 64])
sp_core::ed25519::Signature::default()
}
let mut client = TestClientBuilder::new().build();
+3 -3
View File
@@ -1466,14 +1466,14 @@ where
fn sr25519_verify(&self, signature: &[u8; 64], message: &[u8], pub_key: &[u8; 32]) -> bool {
sp_io::crypto::sr25519_verify(
&SR25519Signature(*signature),
&SR25519Signature::from(*signature),
message,
&SR25519Public(*pub_key),
&SR25519Public::from(*pub_key),
)
}
fn ecdsa_to_eth_address(&self, pk: &[u8; 33]) -> Result<[u8; 20], ()> {
ECDSAPublic(*pk).to_eth_address()
ECDSAPublic::from(*pk).to_eth_address()
}
#[cfg(test)]
@@ -139,8 +139,8 @@ mod benchmarks {
TicketsIds::<T>::insert((epoch_tag as u8, i), id);
let body = TicketBody {
attempt_idx: i,
erased_public: EphemeralPublic([i as u8; 32]),
revealed_public: EphemeralPublic([i as u8; 32]),
erased_public: EphemeralPublic::from([i as u8; 32]),
revealed_public: EphemeralPublic::from([i as u8; 32]),
};
TicketsData::<T>::set(id, Some(body));
});
@@ -236,8 +236,8 @@ mod benchmarks {
.map(|i| {
let body = TicketBody {
attempt_idx: i,
erased_public: EphemeralPublic([i as u8; 32]),
revealed_public: EphemeralPublic([i as u8; 32]),
erased_public: EphemeralPublic::from([i as u8; 32]),
revealed_public: EphemeralPublic::from([i as u8; 32]),
};
let id_bytes = crate::hashing::blake2_128(&i.to_le_bytes());
let id = TicketId::from_le_bytes(id_bytes);
@@ -13,8 +13,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied
|
= help: the following other types implement trait `WrapperTypeDecode`:
Box<T>
Rc<T>
frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes
Rc<T>
Arc<T>
= note: required for `Bar` to implement `Decode`
= note: required for `Bar` to implement `FullCodec`
@@ -65,8 +65,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied
bytes::bytes::Bytes
Cow<'a, T>
parity_scale_codec::Ref<'a, T, U>
Rc<T>
frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes
Rc<T>
Arc<T>
Vec<T>
and $N others
@@ -106,8 +106,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied
|
= help: the following other types implement trait `WrapperTypeDecode`:
Box<T>
Rc<T>
frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes
Rc<T>
Arc<T>
= note: required for `Bar` to implement `Decode`
= note: required for `Bar` to implement `FullCodec`
@@ -148,8 +148,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied
bytes::bytes::Bytes
Cow<'a, T>
parity_scale_codec::Ref<'a, T, U>
Rc<T>
frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes
Rc<T>
Arc<T>
Vec<T>
and $N others
@@ -168,8 +168,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied
|
= help: the following other types implement trait `WrapperTypeDecode`:
Box<T>
Rc<T>
frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes
Rc<T>
Arc<T>
= note: required for `Bar` to implement `Decode`
= note: required for `Bar` to implement `FullCodec`
@@ -210,8 +210,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied
bytes::bytes::Bytes
Cow<'a, T>
parity_scale_codec::Ref<'a, T, U>
Rc<T>
frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes
Rc<T>
Arc<T>
Vec<T>
and $N others
@@ -13,8 +13,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied
|
= help: the following other types implement trait `WrapperTypeDecode`:
Box<T>
Rc<T>
frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes
Rc<T>
Arc<T>
= note: required for `Bar` to implement `Decode`
= note: required for `Bar` to implement `FullCodec`
@@ -65,8 +65,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied
bytes::bytes::Bytes
Cow<'a, T>
parity_scale_codec::Ref<'a, T, U>
Rc<T>
frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes
Rc<T>
Arc<T>
Vec<T>
and $N others
@@ -106,8 +106,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied
|
= help: the following other types implement trait `WrapperTypeDecode`:
Box<T>
Rc<T>
frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes
Rc<T>
Arc<T>
= note: required for `Bar` to implement `Decode`
= note: required for `Bar` to implement `FullCodec`
@@ -148,8 +148,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied
bytes::bytes::Bytes
Cow<'a, T>
parity_scale_codec::Ref<'a, T, U>
Rc<T>
frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes
Rc<T>
Arc<T>
Vec<T>
and $N others
@@ -168,8 +168,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied
|
= help: the following other types implement trait `WrapperTypeDecode`:
Box<T>
Rc<T>
frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes
Rc<T>
Arc<T>
= note: required for `Bar` to implement `Decode`
= note: required for `Bar` to implement `FullCodec`
@@ -210,8 +210,8 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied
bytes::bytes::Bytes
Cow<'a, T>
parity_scale_codec::Ref<'a, T, U>
Rc<T>
frame_support::sp_runtime::sp_application_crypto::sp_core::Bytes
Rc<T>
Arc<T>
Vec<T>
and $N others
+19 -104
View File
@@ -26,7 +26,8 @@ use crate::crypto::Ss58Codec;
use crate::crypto::VrfSecret;
use crate::crypto::{
ByteArray, CryptoType, CryptoTypeId, Derive, DeriveError, DeriveJunction, Pair as TraitPair,
Public as TraitPublic, SecretStringError, UncheckedFrom, VrfPublic,
Public as TraitPublic, PublicBytes, SecretStringError, SignatureBytes, UncheckedFrom,
VrfPublic,
};
#[cfg(feature = "serde")]
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
@@ -37,7 +38,6 @@ use bandersnatch_vrfs::{CanonicalSerialize, SecretKey};
use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};
use scale_info::TypeInfo;
use sp_runtime_interface::pass_by::PassByInner;
use sp_std::{vec, vec::Vec};
/// Identifier used to match public keys against bandersnatch-vrf keys.
@@ -46,69 +46,23 @@ pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"band");
/// Context used to produce a plain signature without any VRF input/output.
pub const SIGNING_CTX: &[u8] = b"BandersnatchSigningContext";
const SEED_SERIALIZED_SIZE: usize = 32;
/// The byte length of secret key seed.
pub const SEED_SERIALIZED_SIZE: usize = 32;
const PUBLIC_SERIALIZED_SIZE: usize = 33;
const SIGNATURE_SERIALIZED_SIZE: usize = 65;
const PREOUT_SERIALIZED_SIZE: usize = 33;
/// The byte length of serialized public key.
pub const PUBLIC_SERIALIZED_SIZE: usize = 33;
/// The byte length of serialized signature.
pub const SIGNATURE_SERIALIZED_SIZE: usize = 65;
/// The byte length of serialized pre-output.
pub const PREOUT_SERIALIZED_SIZE: usize = 33;
#[doc(hidden)]
pub struct BandersnatchTag;
/// Bandersnatch public key.
#[derive(
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Encode,
Decode,
PassByInner,
MaxEncodedLen,
TypeInfo,
Hash,
)]
pub struct Public(pub [u8; PUBLIC_SERIALIZED_SIZE]);
impl UncheckedFrom<[u8; PUBLIC_SERIALIZED_SIZE]> for Public {
fn unchecked_from(raw: [u8; PUBLIC_SERIALIZED_SIZE]) -> Self {
Public(raw)
}
}
impl AsRef<[u8; PUBLIC_SERIALIZED_SIZE]> for Public {
fn as_ref(&self) -> &[u8; PUBLIC_SERIALIZED_SIZE] {
&self.0
}
}
impl AsRef<[u8]> for Public {
fn as_ref(&self) -> &[u8] {
&self.0[..]
}
}
impl AsMut<[u8]> for Public {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.0[..]
}
}
impl TryFrom<&[u8]> for Public {
type Error = ();
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
if data.len() != PUBLIC_SERIALIZED_SIZE {
return Err(())
}
let mut r = [0u8; PUBLIC_SERIALIZED_SIZE];
r.copy_from_slice(data);
Ok(Self::unchecked_from(r))
}
}
impl ByteArray for Public {
const LEN: usize = PUBLIC_SERIALIZED_SIZE;
}
pub type Public = PublicBytes<PUBLIC_SERIALIZED_SIZE, BandersnatchTag>;
impl TraitPublic for Public {}
@@ -150,45 +104,7 @@ impl<'de> Deserialize<'de> for Public {
///
/// The signature is created via the [`VrfSecret::vrf_sign`] using [`SIGNING_CTX`] as transcript
/// `label`.
#[derive(
Clone, Copy, PartialEq, Eq, Encode, Decode, PassByInner, MaxEncodedLen, TypeInfo, Hash,
)]
pub struct Signature([u8; SIGNATURE_SERIALIZED_SIZE]);
impl UncheckedFrom<[u8; SIGNATURE_SERIALIZED_SIZE]> for Signature {
fn unchecked_from(raw: [u8; SIGNATURE_SERIALIZED_SIZE]) -> Self {
Signature(raw)
}
}
impl AsRef<[u8]> for Signature {
fn as_ref(&self) -> &[u8] {
&self.0[..]
}
}
impl AsMut<[u8]> for Signature {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.0[..]
}
}
impl TryFrom<&[u8]> for Signature {
type Error = ();
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
if data.len() != SIGNATURE_SERIALIZED_SIZE {
return Err(())
}
let mut r = [0u8; SIGNATURE_SERIALIZED_SIZE];
r.copy_from_slice(data);
Ok(Self::unchecked_from(r))
}
}
impl ByteArray for Signature {
const LEN: usize = SIGNATURE_SERIALIZED_SIZE;
}
pub type Signature = SignatureBytes<SIGNATURE_SERIALIZED_SIZE, BandersnatchTag>;
impl CryptoType for Signature {
type Pair = Pair;
@@ -542,8 +458,7 @@ pub mod vrf {
thin_signature.preouts.into_iter().map(VrfPreOutput).collect();
let pre_outputs = VrfIosVec::truncate_from(pre_outputs);
let mut signature =
VrfSignature { signature: Signature([0; SIGNATURE_SERIALIZED_SIZE]), pre_outputs };
let mut signature = VrfSignature { signature: Signature::default(), pre_outputs };
thin_signature
.proof
@@ -582,7 +497,7 @@ pub mod vrf {
// This is another hack used because backend signature type is generic over
// the number of ios.
let Ok(proof) = ThinVrfSignature::<0>::deserialize_compressed_unchecked(
signature.signature.as_ref(),
signature.signature.as_slice(),
)
.map(|s| s.proof) else {
return false
+15 -199
View File
@@ -26,28 +26,21 @@
#[cfg(feature = "serde")]
use crate::crypto::Ss58Codec;
use crate::crypto::{
ByteArray, CryptoType, Derive, DeriveError, DeriveJunction, Pair as TraitPair,
Public as TraitPublic, SecretStringError, UncheckedFrom,
CryptoType, Derive, DeriveError, DeriveJunction, Pair as TraitPair, Public as TraitPublic,
PublicBytes, SecretStringError, SignatureBytes, UncheckedFrom,
};
use sp_std::vec::Vec;
use codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
#[cfg(feature = "serde")]
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
#[cfg(all(not(feature = "std"), feature = "serde"))]
use sp_std::alloc::{format, string::String};
use sp_std::vec::Vec;
use w3f_bls::{
DoublePublicKey, DoublePublicKeyScheme, DoubleSignature, EngineBLS, Keypair, Message,
SecretKey, SerializableToBytes, TinyBLS381,
};
use sp_runtime_interface::pass_by::{self, PassBy, PassByInner};
use sp_std::{convert::TryFrom, marker::PhantomData, ops::Deref};
/// BLS-377 specialized types
pub mod bls377 {
pub use super::{PUBLIC_KEY_SERIALIZED_SIZE, SIGNATURE_SERIALIZED_SIZE};
@@ -57,6 +50,9 @@ pub mod bls377 {
/// An identifier used to match public keys against BLS12-377 keys
pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"bls7");
#[doc(hidden)]
pub type Bls377Tag = TinyBLS377;
/// BLS12-377 key pair.
pub type Pair = super::Pair<TinyBLS377>;
/// BLS12-377 public key.
@@ -113,114 +109,11 @@ pub const SIGNATURE_SERIALIZED_SIZE: usize =
/// will need it later (such as for HDKD).
type Seed = [u8; SECRET_KEY_SERIALIZED_SIZE];
#[doc(hidden)]
pub struct BlsTag;
/// A public key.
#[derive(Copy, Encode, Decode, MaxEncodedLen, TypeInfo)]
#[scale_info(skip_type_params(T))]
pub struct Public<T> {
inner: [u8; PUBLIC_KEY_SERIALIZED_SIZE],
_phantom: PhantomData<fn() -> T>,
}
impl<T> Clone for Public<T> {
fn clone(&self) -> Self {
Self { inner: self.inner, _phantom: PhantomData }
}
}
impl<T> PartialEq for Public<T> {
fn eq(&self, other: &Self) -> bool {
self.inner == other.inner
}
}
impl<T> Eq for Public<T> {}
impl<T> PartialOrd for Public<T> {
fn partial_cmp(&self, other: &Self) -> Option<sp_std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<T> Ord for Public<T> {
fn cmp(&self, other: &Self) -> sp_std::cmp::Ordering {
self.inner.cmp(&other.inner)
}
}
impl<T> sp_std::hash::Hash for Public<T> {
fn hash<H: sp_std::hash::Hasher>(&self, state: &mut H) {
self.inner.hash(state)
}
}
impl<T> ByteArray for Public<T> {
const LEN: usize = PUBLIC_KEY_SERIALIZED_SIZE;
}
impl<T> PassByInner for Public<T> {
type Inner = [u8; PUBLIC_KEY_SERIALIZED_SIZE];
fn into_inner(self) -> Self::Inner {
self.inner
}
fn inner(&self) -> &Self::Inner {
&self.inner
}
fn from_inner(inner: Self::Inner) -> Self {
Self { inner, _phantom: PhantomData }
}
}
impl<T> PassBy for Public<T> {
type PassBy = pass_by::Inner<Self, [u8; PUBLIC_KEY_SERIALIZED_SIZE]>;
}
impl<T> AsRef<[u8; PUBLIC_KEY_SERIALIZED_SIZE]> for Public<T> {
fn as_ref(&self) -> &[u8; PUBLIC_KEY_SERIALIZED_SIZE] {
&self.inner
}
}
impl<T> AsRef<[u8]> for Public<T> {
fn as_ref(&self) -> &[u8] {
&self.inner[..]
}
}
impl<T> AsMut<[u8]> for Public<T> {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.inner[..]
}
}
impl<T> Deref for Public<T> {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<T> TryFrom<&[u8]> for Public<T> {
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<T> From<Public<T>> for [u8; PUBLIC_KEY_SERIALIZED_SIZE] {
fn from(x: Public<T>) -> Self {
x.inner
}
}
pub type Public<SubTag> = PublicBytes<PUBLIC_KEY_SERIALIZED_SIZE, (BlsTag, SubTag)>;
impl<T: BlsBound> From<Pair<T>> for Public<T> {
fn from(x: Pair<T>) -> Self {
@@ -228,12 +121,6 @@ impl<T: BlsBound> From<Pair<T>> for Public<T> {
}
}
impl<T> UncheckedFrom<[u8; PUBLIC_KEY_SERIALIZED_SIZE]> for Public<T> {
fn unchecked_from(data: [u8; PUBLIC_KEY_SERIALIZED_SIZE]) -> Self {
Public { inner: data, _phantom: PhantomData }
}
}
#[cfg(feature = "std")]
impl<T: BlsBound> std::str::FromStr for Public<T> {
type Err = crate::crypto::PublicError;
@@ -254,7 +141,7 @@ impl<T: BlsBound> std::fmt::Display for Public<T> {
impl<T: BlsBound> sp_std::fmt::Debug for Public<T> {
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])
write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.0), &s[0..8])
}
}
@@ -295,49 +182,7 @@ impl<T: BlsBound> CryptoType for Public<T> {
}
/// A generic BLS signature.
#[derive(Copy, Encode, Decode, MaxEncodedLen, TypeInfo)]
#[scale_info(skip_type_params(T))]
pub struct Signature<T> {
inner: [u8; SIGNATURE_SERIALIZED_SIZE],
_phantom: PhantomData<fn() -> T>,
}
impl<T> Clone for Signature<T> {
fn clone(&self) -> Self {
Self { inner: self.inner, _phantom: PhantomData }
}
}
impl<T> PartialEq for Signature<T> {
fn eq(&self, other: &Self) -> bool {
self.inner == other.inner
}
}
impl<T> Eq for Signature<T> {}
impl<T> sp_std::hash::Hash for Signature<T> {
fn hash<H: sp_std::hash::Hasher>(&self, state: &mut H) {
self.inner.hash(state)
}
}
impl<T> ByteArray for Signature<T> {
const LEN: usize = SIGNATURE_SERIALIZED_SIZE;
}
impl<T> TryFrom<&[u8]> for Signature<T> {
type Error = ();
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
if data.len() != SIGNATURE_SERIALIZED_SIZE {
return Err(())
}
let mut inner = [0u8; SIGNATURE_SERIALIZED_SIZE];
inner.copy_from_slice(data);
Ok(Signature::unchecked_from(inner))
}
}
pub type Signature<SubTag> = SignatureBytes<SIGNATURE_SERIALIZED_SIZE, (BlsTag, SubTag)>;
#[cfg(feature = "serde")]
impl<T> Serialize for Signature<T> {
@@ -362,34 +207,10 @@ impl<'de, T> Deserialize<'de> for Signature<T> {
}
}
impl<T> From<Signature<T>> for [u8; SIGNATURE_SERIALIZED_SIZE] {
fn from(signature: Signature<T>) -> [u8; SIGNATURE_SERIALIZED_SIZE] {
signature.inner
}
}
impl<T> AsRef<[u8; SIGNATURE_SERIALIZED_SIZE]> for Signature<T> {
fn as_ref(&self) -> &[u8; SIGNATURE_SERIALIZED_SIZE] {
&self.inner
}
}
impl<T> AsRef<[u8]> for Signature<T> {
fn as_ref(&self) -> &[u8] {
&self.inner[..]
}
}
impl<T> AsMut<[u8]> for Signature<T> {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.inner[..]
}
}
impl<T> sp_std::fmt::Debug for Signature<T> {
#[cfg(feature = "std")]
fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.inner))
write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.0))
}
#[cfg(not(feature = "std"))]
@@ -398,12 +219,6 @@ impl<T> sp_std::fmt::Debug for Signature<T> {
}
}
impl<T> UncheckedFrom<[u8; SIGNATURE_SERIALIZED_SIZE]> for Signature<T> {
fn unchecked_from(data: [u8; SIGNATURE_SERIALIZED_SIZE]) -> Self {
Signature { inner: data, _phantom: PhantomData }
}
}
impl<T: BlsBound> CryptoType for Signature<T> {
type Pair = Pair<T>;
}
@@ -423,6 +238,7 @@ trait HardJunctionId {
/// Derive a single hard junction.
fn derive_hard_junction<T: HardJunctionId>(secret_seed: &Seed, cc: &[u8; 32]) -> Seed {
use codec::Encode;
(T::ID, secret_seed, cc).using_encoded(sp_crypto_hashing::blake2_256)
}
@@ -489,7 +305,7 @@ impl<T: BlsBound> TraitPair for Pair<T> {
Err(_) => return false,
};
let sig_array = match sig.inner[..].try_into() {
let sig_array = match sig.0[..].try_into() {
Ok(s) => s,
Err(_) => return false,
};
+4 -1
View File
@@ -39,7 +39,10 @@ pub use ss58_registry::{from_known_address_format, Ss58AddressFormat, Ss58Addres
/// Trait to zeroize a memory buffer.
pub use zeroize::Zeroize;
pub use crate::address_uri::{AddressUri, Error as AddressUriError};
pub use crate::{
address_uri::{AddressUri, Error as AddressUriError},
crypto_bytes::{CryptoBytes, PublicBytes, SignatureBytes},
};
/// The root phrase for our publicly known keys.
pub const DEV_PHRASE: &str =
@@ -0,0 +1,244 @@
// 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.
//! Generic byte array which can be specialized with a marker type.
use crate::{
crypto::{FromEntropy, UncheckedFrom},
hash::{H256, H512},
};
use codec::{Decode, Encode, MaxEncodedLen};
use core::marker::PhantomData;
use scale_info::TypeInfo;
use sp_runtime_interface::pass_by::{self, PassBy, PassByInner};
/// Generic byte array holding some crypto-related raw data.
///
/// The type is generic over a constant length `N` and a "tag" `T` which
/// can be used to specialize the byte array without requiring newtypes.
///
/// The tag `T` is held in a `PhantomData<fn() ->T>`, a trick allowing
/// `CryptoBytes` to be `Send` and `Sync` regardless of `T` properties
/// ([ref](https://doc.rust-lang.org/nomicon/phantom-data.html#table-of-phantomdata-patterns)).
#[derive(Encode, Decode, MaxEncodedLen)]
#[repr(transparent)]
pub struct CryptoBytes<const N: usize, T = ()>(pub [u8; N], PhantomData<fn() -> T>);
impl<const N: usize, T> Copy for CryptoBytes<N, T> {}
impl<const N: usize, T> Clone for CryptoBytes<N, T> {
fn clone(&self) -> Self {
Self(self.0, PhantomData)
}
}
impl<const N: usize, T> TypeInfo for CryptoBytes<N, T> {
type Identity = [u8; N];
fn type_info() -> scale_info::Type {
Self::Identity::type_info()
}
}
impl<const N: usize, T> PartialOrd for CryptoBytes<N, T> {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
self.0.partial_cmp(&other.0)
}
}
impl<const N: usize, T> Ord for CryptoBytes<N, T> {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.0.cmp(&other.0)
}
}
impl<const N: usize, T> PartialEq for CryptoBytes<N, T> {
fn eq(&self, other: &Self) -> bool {
self.0.eq(&other.0)
}
}
impl<const N: usize, T> core::hash::Hash for CryptoBytes<N, T> {
fn hash<H: scale_info::prelude::hash::Hasher>(&self, state: &mut H) {
self.0.hash(state)
}
}
impl<const N: usize, T> Eq for CryptoBytes<N, T> {}
impl<const N: usize, T> Default for CryptoBytes<N, T> {
fn default() -> Self {
Self([0_u8; N], PhantomData)
}
}
impl<const N: usize, T> PassByInner for CryptoBytes<N, T> {
type Inner = [u8; N];
fn into_inner(self) -> Self::Inner {
self.0
}
fn inner(&self) -> &Self::Inner {
&self.0
}
fn from_inner(inner: Self::Inner) -> Self {
Self(inner, PhantomData)
}
}
impl<const N: usize, T> PassBy for CryptoBytes<N, T> {
type PassBy = pass_by::Inner<Self, [u8; N]>;
}
impl<const N: usize, T> AsRef<[u8]> for CryptoBytes<N, T> {
fn as_ref(&self) -> &[u8] {
&self.0[..]
}
}
impl<const N: usize, T> AsMut<[u8]> for CryptoBytes<N, T> {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.0[..]
}
}
impl<const N: usize, T> From<CryptoBytes<N, T>> for [u8; N] {
fn from(v: CryptoBytes<N, T>) -> [u8; N] {
v.0
}
}
impl<const N: usize, T> AsRef<[u8; N]> for CryptoBytes<N, T> {
fn as_ref(&self) -> &[u8; N] {
&self.0
}
}
impl<const N: usize, T> AsMut<[u8; N]> for CryptoBytes<N, T> {
fn as_mut(&mut self) -> &mut [u8; N] {
&mut self.0
}
}
impl<const N: usize, T> From<[u8; N]> for CryptoBytes<N, T> {
fn from(value: [u8; N]) -> Self {
Self::from_raw(value)
}
}
impl<const N: usize, T> TryFrom<&[u8]> for CryptoBytes<N, T> {
type Error = ();
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
if data.len() != N {
return Err(())
}
let mut r = [0u8; N];
r.copy_from_slice(data);
Ok(Self::from_raw(r))
}
}
impl<const N: usize, T> UncheckedFrom<[u8; N]> for CryptoBytes<N, T> {
fn unchecked_from(data: [u8; N]) -> Self {
Self::from_raw(data)
}
}
impl<const N: usize, T> core::ops::Deref for CryptoBytes<N, T> {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<const N: usize, T> CryptoBytes<N, T> {
/// Construct from raw array.
pub fn from_raw(inner: [u8; N]) -> Self {
Self(inner, PhantomData)
}
/// Construct from raw array.
pub fn to_raw(self) -> [u8; N] {
self.0
}
/// Return a slice filled with raw data.
pub fn as_array_ref(&self) -> &[u8; N] {
&self.0
}
}
impl<const N: usize, T> crate::ByteArray for CryptoBytes<N, T> {
const LEN: usize = N;
}
impl<const N: usize, T> FromEntropy for CryptoBytes<N, T> {
fn from_entropy(input: &mut impl codec::Input) -> Result<Self, codec::Error> {
let mut result = Self::default();
input.read(result.as_mut())?;
Ok(result)
}
}
impl<T> From<CryptoBytes<32, T>> for H256 {
fn from(x: CryptoBytes<32, T>) -> H256 {
H256::from(x.0)
}
}
impl<T> From<CryptoBytes<64, T>> for H512 {
fn from(x: CryptoBytes<64, T>) -> H512 {
H512::from(x.0)
}
}
impl<T> UncheckedFrom<H256> for CryptoBytes<32, T> {
fn unchecked_from(x: H256) -> Self {
Self::from_h256(x)
}
}
impl<T> CryptoBytes<32, T> {
/// A new instance from an H256.
pub fn from_h256(x: H256) -> Self {
Self::from_raw(x.into())
}
}
impl<T> CryptoBytes<64, T> {
/// A new instance from an H512.
pub fn from_h512(x: H512) -> Self {
Self::from_raw(x.into())
}
}
/// Tag used for generic public key bytes.
pub struct PublicTag;
/// Generic encoded public key.
pub type PublicBytes<const N: usize, SubTag> = CryptoBytes<N, (PublicTag, SubTag)>;
/// Tag used for generic signature bytes.
pub struct SignatureTag;
/// Generic encoded signature.
pub type SignatureBytes<const N: usize, SubTag> = CryptoBytes<N, (SignatureTag, SubTag)>;
+18 -166
View File
@@ -17,15 +17,11 @@
//! Simple ECDSA secp256k1 API.
use codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
use sp_runtime_interface::pass_by::PassByInner;
#[cfg(feature = "serde")]
use crate::crypto::Ss58Codec;
use crate::crypto::{
ByteArray, CryptoType, CryptoTypeId, Derive, DeriveError, DeriveJunction, Pair as TraitPair,
Public as TraitPublic, SecretStringError, UncheckedFrom,
CryptoType, CryptoTypeId, Derive, DeriveError, DeriveJunction, Pair as TraitPair,
Public as TraitPublic, PublicBytes, SecretStringError, SignatureBytes,
};
#[cfg(not(feature = "std"))]
@@ -51,45 +47,18 @@ pub const PUBLIC_KEY_SERIALIZED_SIZE: usize = 33;
/// The byte length of signature
pub const SIGNATURE_SERIALIZED_SIZE: usize = 65;
#[doc(hidden)]
pub struct EcdsaTag;
/// The secret seed.
///
/// The raw secret seed, which can be used to create the `Pair`.
type Seed = [u8; 32];
/// The ECDSA compressed public key.
#[derive(
Clone,
Copy,
Encode,
Decode,
PassByInner,
MaxEncodedLen,
TypeInfo,
Eq,
PartialEq,
PartialOrd,
Ord,
Hash,
)]
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; PUBLIC_KEY_SERIALIZED_SIZE]);
input.read(&mut result.0[..])?;
Ok(result)
}
}
pub type Public = PublicBytes<PUBLIC_KEY_SERIALIZED_SIZE, EcdsaTag>;
impl Public {
/// A new instance from the given 33-byte `data`.
///
/// 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; PUBLIC_KEY_SERIALIZED_SIZE]) -> Self {
Self(data)
}
/// Create a new instance from the given full public key.
///
/// This will convert the full public key into the compressed format.
@@ -111,54 +80,22 @@ impl Public {
}
}
impl ByteArray for Public {
const LEN: usize = PUBLIC_KEY_SERIALIZED_SIZE;
}
impl TraitPublic for Public {}
impl Derive for Public {}
impl AsRef<[u8]> for Public {
fn as_ref(&self) -> &[u8] {
&self.0[..]
}
}
impl AsMut<[u8]> for Public {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.0[..]
}
}
#[cfg(feature = "std")]
impl From<PublicKey> for Public {
fn from(pubkey: PublicKey) -> Self {
Self(pubkey.serialize())
Self::from(pubkey.serialize())
}
}
#[cfg(not(feature = "std"))]
impl From<VerifyingKey> for Public {
fn from(pubkey: VerifyingKey) -> Self {
Self::unchecked_from(
pubkey.to_sec1_bytes()[..]
.try_into()
.expect("valid key is serializable to [u8,33]. qed."),
)
}
}
impl TryFrom<&[u8]> for Public {
type Error = ();
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
if data.len() != Self::LEN {
return Err(())
}
let mut r = [0u8; Self::LEN];
r.copy_from_slice(data);
Ok(Self::unchecked_from(r))
Self::try_from(&pubkey.to_sec1_bytes()[..])
.expect("Valid key is serializable to [u8; 33]. qed.")
}
}
@@ -169,12 +106,6 @@ impl From<Pair> for Public {
}
}
impl UncheckedFrom<[u8; PUBLIC_KEY_SERIALIZED_SIZE]> for Public {
fn unchecked_from(x: [u8; PUBLIC_KEY_SERIALIZED_SIZE]) -> Self {
Public(x)
}
}
#[cfg(feature = "std")]
impl std::fmt::Display for Public {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
@@ -217,26 +148,7 @@ impl<'de> Deserialize<'de> for Public {
}
/// A signature (a 512-bit value, plus 8 bits for recovery ID).
#[derive(Hash, 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 = ();
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
if data.len() == SIGNATURE_SERIALIZED_SIZE {
let mut inner = [0u8; SIGNATURE_SERIALIZED_SIZE];
inner.copy_from_slice(data);
Ok(Signature(inner))
} else {
Err(())
}
}
}
pub type Signature = SignatureBytes<SIGNATURE_SERIALIZED_SIZE, EcdsaTag>;
#[cfg(feature = "serde")]
impl Serialize for Signature {
@@ -261,44 +173,6 @@ impl<'de> Deserialize<'de> for Signature {
}
}
impl Clone for Signature {
fn clone(&self) -> Self {
let mut r = [0u8; SIGNATURE_SERIALIZED_SIZE];
r.copy_from_slice(&self.0[..]);
Signature(r)
}
}
impl Default for Signature {
fn default() -> Self {
Signature([0u8; SIGNATURE_SERIALIZED_SIZE])
}
}
impl From<Signature> for [u8; SIGNATURE_SERIALIZED_SIZE] {
fn from(v: Signature) -> [u8; SIGNATURE_SERIALIZED_SIZE] {
v.0
}
}
impl AsRef<[u8; SIGNATURE_SERIALIZED_SIZE]> for Signature {
fn as_ref(&self) -> &[u8; SIGNATURE_SERIALIZED_SIZE] {
&self.0
}
}
impl AsRef<[u8]> for Signature {
fn as_ref(&self) -> &[u8] {
&self.0[..]
}
}
impl AsMut<[u8]> for Signature {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.0[..]
}
}
impl sp_std::fmt::Debug for Signature {
#[cfg(feature = "std")]
fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
@@ -311,34 +185,7 @@ impl sp_std::fmt::Debug for Signature {
}
}
impl UncheckedFrom<[u8; SIGNATURE_SERIALIZED_SIZE]> for Signature {
fn unchecked_from(data: [u8; SIGNATURE_SERIALIZED_SIZE]) -> Signature {
Signature(data)
}
}
impl Signature {
/// A new instance from the given 65-byte `data`.
///
/// 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; SIGNATURE_SERIALIZED_SIZE]) -> Signature {
Signature(data)
}
/// A new instance from the given slice that should be 65 bytes long.
///
/// 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() != SIGNATURE_SERIALIZED_SIZE {
return None
}
let mut r = [0u8; SIGNATURE_SERIALIZED_SIZE];
r.copy_from_slice(data);
Some(Signature(r))
}
/// Recover the public key from this signature and a message.
pub fn recover<M: AsRef<[u8]>>(&self, message: M) -> Option<Public> {
self.recover_prehashed(&sp_crypto_hashing::blake2_256(message.as_ref()))
@@ -350,7 +197,8 @@ impl Signature {
{
let rid = RecoveryId::from_i32(self.0[64] as i32).ok()?;
let sig = RecoverableSignature::from_compact(&self.0[..64], rid).ok()?;
let message = Message::from_digest_slice(message).expect("Message is 32 bytes; qed");
let message =
Message::from_digest_slice(message).expect("Message is a 32 bytes hash; qed");
SECP256K1.recover_ecdsa(&message, &sig).ok().map(Public::from)
}
@@ -387,6 +235,7 @@ impl From<RecoverableSignature> for Signature {
/// Derive a single hard junction.
fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed {
use codec::Encode;
("Secp256k1HDKD", secret_seed, cc).using_encoded(sp_crypto_hashing::blake2_256)
}
@@ -490,15 +339,18 @@ impl Pair {
pub fn sign_prehashed(&self, message: &[u8; 32]) -> Signature {
#[cfg(feature = "std")]
{
let message = Message::from_digest_slice(message).expect("Message is 32 bytes; qed");
let message =
Message::from_digest_slice(message).expect("Message is a 32 bytes hash; qed");
SECP256K1.sign_ecdsa_recoverable(&message, &self.secret).into()
}
#[cfg(not(feature = "std"))]
{
// Signing fails only if the `message` number of bytes is less than the field length
// (unfallible as we're using a fixed message length of 32).
self.secret
.sign_prehash_recoverable(message)
.expect("signing may not fail (???). qed.")
.expect("Signing can't fail when using 32 bytes message hash. qed.")
.into()
}
}
+25 -230
View File
@@ -15,119 +15,45 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// tag::description[]
//! Simple Ed25519 API.
// end::description[]
use sp_std::vec::Vec;
use crate::{
crypto::ByteArray,
hash::{H256, H512},
};
use codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
#[cfg(feature = "serde")]
use crate::crypto::Ss58Codec;
use crate::crypto::{
CryptoType, CryptoTypeId, Derive, DeriveError, DeriveJunction, FromEntropy, Pair as TraitPair,
Public as TraitPublic, SecretStringError, UncheckedFrom,
ByteArray, CryptoType, CryptoTypeId, Derive, DeriveError, DeriveJunction, Pair as TraitPair,
Public as TraitPublic, PublicBytes, SecretStringError, SignatureBytes,
};
#[cfg(feature = "full_crypto")]
use core::convert::TryFrom;
use ed25519_zebra::{SigningKey, VerificationKey};
#[cfg(feature = "serde")]
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use sp_runtime_interface::pass_by::PassByInner;
#[cfg(all(not(feature = "std"), feature = "serde"))]
use sp_std::alloc::{format, string::String};
use sp_std::ops::Deref;
use sp_std::vec::Vec;
/// An identifier used to match public keys against ed25519 keys
pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ed25");
/// The byte length of public key
pub const PUBLIC_KEY_SERIALIZED_SIZE: usize = 32;
/// The byte length of signature
pub const SIGNATURE_SERIALIZED_SIZE: usize = 64;
/// 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).
type Seed = [u8; 32];
#[doc(hidden)]
pub struct Ed25519Tag;
/// A public key.
#[derive(
PartialEq,
Eq,
PartialOrd,
Ord,
Clone,
Copy,
Encode,
Decode,
PassByInner,
MaxEncodedLen,
TypeInfo,
Hash,
)]
pub struct Public(pub [u8; 32]);
pub type Public = PublicBytes<PUBLIC_KEY_SERIALIZED_SIZE, Ed25519Tag>;
/// A key pair.
#[derive(Copy, Clone)]
pub struct Pair {
public: VerificationKey,
secret: SigningKey,
}
impl TraitPublic for Public {}
impl FromEntropy for Public {
fn from_entropy(input: &mut impl codec::Input) -> Result<Self, codec::Error> {
let mut result = Self([0u8; 32]);
input.read(&mut result.0[..])?;
Ok(result)
}
}
impl AsRef<[u8; 32]> for Public {
fn as_ref(&self) -> &[u8; 32] {
&self.0
}
}
impl AsRef<[u8]> for Public {
fn as_ref(&self) -> &[u8] {
&self.0[..]
}
}
impl AsMut<[u8]> for Public {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.0[..]
}
}
impl Deref for Public {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl TryFrom<&[u8]> for Public {
type Error = ();
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
if data.len() != Self::LEN {
return Err(())
}
let mut r = [0u8; Self::LEN];
r.copy_from_slice(data);
Ok(Self::unchecked_from(r))
}
}
impl From<Public> for [u8; 32] {
fn from(x: Public) -> Self {
x.0
}
}
impl Derive for Public {}
#[cfg(feature = "full_crypto")]
impl From<Pair> for Public {
@@ -136,12 +62,6 @@ impl From<Pair> for Public {
}
}
impl From<Public> for H256 {
fn from(x: Public) -> Self {
x.0.into()
}
}
#[cfg(feature = "std")]
impl std::str::FromStr for Public {
type Err = crate::crypto::PublicError;
@@ -151,18 +71,6 @@ impl std::str::FromStr for Public {
}
}
impl UncheckedFrom<[u8; 32]> for Public {
fn unchecked_from(x: [u8; 32]) -> Self {
Public::from_raw(x)
}
}
impl UncheckedFrom<H256> for Public {
fn unchecked_from(x: H256) -> Self {
Public::from_h256(x)
}
}
#[cfg(feature = "std")]
impl std::fmt::Display for Public {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
@@ -204,23 +112,8 @@ impl<'de> Deserialize<'de> for Public {
}
}
/// A signature (a 512-bit value).
#[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq, Hash)]
pub struct Signature(pub [u8; 64]);
impl TryFrom<&[u8]> for Signature {
type Error = ();
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
if data.len() == 64 {
let mut inner = [0u8; 64];
inner.copy_from_slice(data);
Ok(Signature(inner))
} else {
Err(())
}
}
}
/// A signature.
pub type Signature = SignatureBytes<SIGNATURE_SERIALIZED_SIZE, Ed25519Tag>;
#[cfg(feature = "serde")]
impl Serialize for Signature {
@@ -245,44 +138,6 @@ impl<'de> Deserialize<'de> for Signature {
}
}
impl Clone for Signature {
fn clone(&self) -> Self {
let mut r = [0u8; 64];
r.copy_from_slice(&self.0[..]);
Signature(r)
}
}
impl From<Signature> for H512 {
fn from(v: Signature) -> H512 {
H512::from(v.0)
}
}
impl From<Signature> for [u8; 64] {
fn from(v: Signature) -> [u8; 64] {
v.0
}
}
impl AsRef<[u8; 64]> for Signature {
fn as_ref(&self) -> &[u8; 64] {
&self.0
}
}
impl AsRef<[u8]> for Signature {
fn as_ref(&self) -> &[u8] {
&self.0[..]
}
}
impl AsMut<[u8]> for Signature {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.0[..]
}
}
impl sp_std::fmt::Debug for Signature {
#[cfg(feature = "std")]
fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
@@ -295,76 +150,16 @@ impl sp_std::fmt::Debug for Signature {
}
}
impl UncheckedFrom<[u8; 64]> for Signature {
fn unchecked_from(data: [u8; 64]) -> Signature {
Signature(data)
}
/// A key pair.
#[derive(Copy, Clone)]
pub struct Pair {
public: VerificationKey,
secret: SigningKey,
}
impl Signature {
/// A new instance from the given 64-byte `data`.
///
/// 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; 64]) -> Signature {
Signature(data)
}
/// A new instance from the given slice that should be 64 bytes long.
///
/// 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() != 64 {
return None
}
let mut r = [0u8; 64];
r.copy_from_slice(data);
Some(Signature(r))
}
/// A new instance from an H512.
///
/// 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_h512(v: H512) -> Signature {
Signature(v.into())
}
}
impl Public {
/// A new instance from the given 32-byte `data`.
///
/// 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; 32]) -> Self {
Public(data)
}
/// A new instance from an H256.
///
/// 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_h256(x: H256) -> Self {
Public(x.into())
}
/// Return a slice filled with raw data.
pub fn as_array_ref(&self) -> &[u8; 32] {
self.as_ref()
}
}
impl ByteArray for Public {
const LEN: usize = 32;
}
impl TraitPublic for Public {}
impl Derive for Public {}
/// Derive a single hard junction.
fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed {
use codec::Encode;
("Ed25519HDKD", secret_seed, cc).using_encoded(sp_crypto_hashing::blake2_256)
}
@@ -402,7 +197,7 @@ impl TraitPair for Pair {
/// Get the public key.
fn public(&self) -> Public {
Public(self.public.into())
Public::from_raw(self.public.into())
}
/// Sign a message.
+1
View File
@@ -62,6 +62,7 @@ mod address_uri;
pub mod bandersnatch;
#[cfg(feature = "bls-experimental")]
pub mod bls;
pub mod crypto_bytes;
pub mod defer;
pub mod ecdsa;
pub mod ed25519;
+91 -176
View File
@@ -17,25 +17,22 @@
//! API for using a pair of crypto schemes together.
use core::marker::PhantomData;
#[cfg(feature = "serde")]
use crate::crypto::Ss58Codec;
use crate::crypto::{
ByteArray, CryptoType, Derive, DeriveError, DeriveJunction, Pair as PairT, Public as PublicT,
SecretStringError, UncheckedFrom,
PublicBytes, SecretStringError, SignatureBytes, UncheckedFrom,
};
use sp_std::vec::Vec;
use codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
#[cfg(feature = "serde")]
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
#[cfg(all(not(feature = "std"), feature = "serde"))]
use sp_std::alloc::{format, string::String};
use sp_runtime_interface::pass_by::{self, PassBy, PassByInner};
use sp_std::convert::TryFrom;
/// ECDSA and BLS12-377 paired crypto scheme
#[cfg(feature = "bls-experimental")]
pub mod ecdsa_bls377 {
@@ -54,12 +51,20 @@ pub mod ecdsa_bls377 {
const SIGNATURE_LEN: usize =
ecdsa::SIGNATURE_SERIALIZED_SIZE + bls377::SIGNATURE_SERIALIZED_SIZE;
#[doc(hidden)]
pub struct EcdsaBls377Tag(ecdsa::EcdsaTag, bls377::Bls377Tag);
impl super::PairedCryptoSubTagBound for EcdsaBls377Tag {}
/// (ECDSA,BLS12-377) key-pair pair.
pub type Pair = super::Pair<ecdsa::Pair, bls377::Pair, PUBLIC_KEY_LEN, SIGNATURE_LEN>;
pub type Pair =
super::Pair<ecdsa::Pair, bls377::Pair, PUBLIC_KEY_LEN, SIGNATURE_LEN, EcdsaBls377Tag>;
/// (ECDSA,BLS12-377) public key pair.
pub type Public = super::Public<PUBLIC_KEY_LEN>;
pub type Public = super::Public<PUBLIC_KEY_LEN, EcdsaBls377Tag>;
/// (ECDSA,BLS12-377) signature pair.
pub type Signature = super::Signature<SIGNATURE_LEN>;
pub type Signature = super::Signature<SIGNATURE_LEN, EcdsaBls377Tag>;
impl super::CryptoType for Public {
type Pair = Pair;
@@ -110,7 +115,7 @@ pub mod ecdsa_bls377 {
let Ok(left_pub) = public.0[..ecdsa::PUBLIC_KEY_SERIALIZED_SIZE].try_into() else {
return false
};
let Ok(left_sig) = sig.0[0..ecdsa::SIGNATURE_SERIALIZED_SIZE].try_into() else {
let Ok(left_sig) = sig.0[..ecdsa::SIGNATURE_SERIALIZED_SIZE].try_into() else {
return false
};
if !ecdsa::Pair::verify_prehashed(&left_sig, &msg_hash, &left_pub) {
@@ -140,110 +145,49 @@ const SECURE_SEED_LEN: usize = 32;
/// will need it later (such as for HDKD).
type Seed = [u8; SECURE_SEED_LEN];
#[doc(hidden)]
pub trait PairedCryptoSubTagBound {}
#[doc(hidden)]
pub struct PairedCryptoTag;
/// A public key.
#[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq, PartialOrd, Ord)]
pub struct Public<const LEFT_PLUS_RIGHT_LEN: usize>([u8; LEFT_PLUS_RIGHT_LEN]);
impl<const LEFT_PLUS_RIGHT_LEN: usize> sp_std::hash::Hash for Public<LEFT_PLUS_RIGHT_LEN> {
fn hash<H: sp_std::hash::Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
impl<const LEFT_PLUS_RIGHT_LEN: usize> ByteArray for Public<LEFT_PLUS_RIGHT_LEN> {
const LEN: usize = LEFT_PLUS_RIGHT_LEN;
}
impl<const LEFT_PLUS_RIGHT_LEN: usize> TryFrom<&[u8]> for Public<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 inner = [0u8; LEFT_PLUS_RIGHT_LEN];
inner.copy_from_slice(data);
Ok(Public(inner))
}
}
impl<const LEFT_PLUS_RIGHT_LEN: usize> AsRef<[u8; LEFT_PLUS_RIGHT_LEN]>
for Public<LEFT_PLUS_RIGHT_LEN>
{
fn as_ref(&self) -> &[u8; LEFT_PLUS_RIGHT_LEN] {
&self.0
}
}
impl<const LEFT_PLUS_RIGHT_LEN: usize> AsRef<[u8]> for Public<LEFT_PLUS_RIGHT_LEN> {
fn as_ref(&self) -> &[u8] {
&self.0[..]
}
}
impl<const LEFT_PLUS_RIGHT_LEN: usize> AsMut<[u8]> for Public<LEFT_PLUS_RIGHT_LEN> {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.0[..]
}
}
impl<const LEFT_PLUS_RIGHT_LEN: usize> PassByInner for Public<LEFT_PLUS_RIGHT_LEN> {
type Inner = [u8; LEFT_PLUS_RIGHT_LEN];
fn into_inner(self) -> Self::Inner {
self.0
}
fn inner(&self) -> &Self::Inner {
&self.0
}
fn from_inner(inner: Self::Inner) -> Self {
Self(inner)
}
}
impl<const LEFT_PLUS_RIGHT_LEN: usize> PassBy for Public<LEFT_PLUS_RIGHT_LEN> {
type PassBy = pass_by::Inner<Self, [u8; LEFT_PLUS_RIGHT_LEN]>;
}
pub type Public<const LEFT_PLUS_RIGHT_LEN: usize, SubTag> =
PublicBytes<LEFT_PLUS_RIGHT_LEN, (PairedCryptoTag, SubTag)>;
impl<
LeftPair: PairT,
RightPair: PairT,
const LEFT_PLUS_RIGHT_PUBLIC_LEN: usize,
const SIGNATURE_LEN: usize,
> From<Pair<LeftPair, RightPair, LEFT_PLUS_RIGHT_PUBLIC_LEN, SIGNATURE_LEN>>
for Public<LEFT_PLUS_RIGHT_PUBLIC_LEN>
SubTag: PairedCryptoSubTagBound,
> From<Pair<LeftPair, RightPair, LEFT_PLUS_RIGHT_PUBLIC_LEN, SIGNATURE_LEN, SubTag>>
for Public<LEFT_PLUS_RIGHT_PUBLIC_LEN, SubTag>
where
Pair<LeftPair, RightPair, LEFT_PLUS_RIGHT_PUBLIC_LEN, SIGNATURE_LEN>:
PairT<Public = Public<LEFT_PLUS_RIGHT_PUBLIC_LEN>>,
Pair<LeftPair, RightPair, LEFT_PLUS_RIGHT_PUBLIC_LEN, SIGNATURE_LEN, SubTag>:
PairT<Public = Public<LEFT_PLUS_RIGHT_PUBLIC_LEN, SubTag>>,
{
fn from(x: Pair<LeftPair, RightPair, LEFT_PLUS_RIGHT_PUBLIC_LEN, SIGNATURE_LEN>) -> Self {
fn from(
x: Pair<LeftPair, RightPair, LEFT_PLUS_RIGHT_PUBLIC_LEN, SIGNATURE_LEN, SubTag>,
) -> Self {
x.public()
}
}
impl<const LEFT_PLUS_RIGHT_LEN: usize> UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]>
for Public<LEFT_PLUS_RIGHT_LEN>
{
fn unchecked_from(data: [u8; LEFT_PLUS_RIGHT_LEN]) -> Self {
Public(data)
}
}
#[cfg(feature = "std")]
impl<const LEFT_PLUS_RIGHT_LEN: usize> std::fmt::Display for Public<LEFT_PLUS_RIGHT_LEN>
impl<const LEFT_PLUS_RIGHT_LEN: usize, SubTag: PairedCryptoSubTagBound> std::fmt::Display
for Public<LEFT_PLUS_RIGHT_LEN, SubTag>
where
Public<LEFT_PLUS_RIGHT_LEN>: CryptoType,
Public<LEFT_PLUS_RIGHT_LEN, SubTag>: CryptoType,
{
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.to_ss58check())
}
}
impl<const LEFT_PLUS_RIGHT_LEN: usize> sp_std::fmt::Debug for Public<LEFT_PLUS_RIGHT_LEN>
impl<const LEFT_PLUS_RIGHT_LEN: usize, SubTag: PairedCryptoSubTagBound> sp_std::fmt::Debug
for Public<LEFT_PLUS_RIGHT_LEN, SubTag>
where
Public<LEFT_PLUS_RIGHT_LEN>: CryptoType,
Public<LEFT_PLUS_RIGHT_LEN, SubTag>: CryptoType,
[u8; LEFT_PLUS_RIGHT_LEN]: crate::hexdisplay::AsBytesRef,
{
#[cfg(feature = "std")]
@@ -259,9 +203,10 @@ where
}
#[cfg(feature = "serde")]
impl<const LEFT_PLUS_RIGHT_LEN: usize> Serialize for Public<LEFT_PLUS_RIGHT_LEN>
impl<const LEFT_PLUS_RIGHT_LEN: usize, SubTag: PairedCryptoSubTagBound> Serialize
for Public<LEFT_PLUS_RIGHT_LEN, SubTag>
where
Public<LEFT_PLUS_RIGHT_LEN>: CryptoType,
Public<LEFT_PLUS_RIGHT_LEN, SubTag>: CryptoType,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
@@ -272,9 +217,10 @@ where
}
#[cfg(feature = "serde")]
impl<'de, const LEFT_PLUS_RIGHT_LEN: usize> Deserialize<'de> for Public<LEFT_PLUS_RIGHT_LEN>
impl<'de, const LEFT_PLUS_RIGHT_LEN: usize, SubTag: PairedCryptoSubTagBound> Deserialize<'de>
for Public<LEFT_PLUS_RIGHT_LEN, SubTag>
where
Public<LEFT_PLUS_RIGHT_LEN>: CryptoType,
Public<LEFT_PLUS_RIGHT_LEN, SubTag>: CryptoType,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
@@ -285,12 +231,17 @@ where
}
}
impl<const LEFT_PLUS_RIGHT_LEN: usize> PublicT for Public<LEFT_PLUS_RIGHT_LEN> where
Public<LEFT_PLUS_RIGHT_LEN>: CryptoType
impl<const LEFT_PLUS_RIGHT_LEN: usize, SubTag: PairedCryptoSubTagBound> PublicT
for Public<LEFT_PLUS_RIGHT_LEN, SubTag>
where
Public<LEFT_PLUS_RIGHT_LEN, SubTag>: CryptoType,
{
}
impl<const LEFT_PLUS_RIGHT_LEN: usize> Derive for Public<LEFT_PLUS_RIGHT_LEN> {}
impl<const LEFT_PLUS_RIGHT_LEN: usize, SubTag: PairedCryptoSubTagBound> Derive
for Public<LEFT_PLUS_RIGHT_LEN, SubTag>
{
}
/// Trait characterizing a signature which could be used as individual component of an
/// `paired_crypto:Signature` pair.
@@ -299,54 +250,13 @@ pub trait SignatureBound: ByteArray {}
impl<T: ByteArray> SignatureBound for T {}
/// A pair of signatures of different types
#[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Eq)]
pub struct Signature<const LEFT_PLUS_RIGHT_LEN: usize>([u8; LEFT_PLUS_RIGHT_LEN]);
impl<const LEFT_PLUS_RIGHT_LEN: usize> sp_std::hash::Hash for Signature<LEFT_PLUS_RIGHT_LEN> {
fn hash<H: sp_std::hash::Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
impl<const LEFT_PLUS_RIGHT_LEN: usize> ByteArray for Signature<LEFT_PLUS_RIGHT_LEN> {
const LEN: usize = LEFT_PLUS_RIGHT_LEN;
}
impl<const LEFT_PLUS_RIGHT_LEN: usize> TryFrom<&[u8]> for Signature<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 inner = [0u8; LEFT_PLUS_RIGHT_LEN];
inner.copy_from_slice(data);
Ok(Signature(inner))
}
}
impl<const LEFT_PLUS_RIGHT_LEN: usize> AsMut<[u8]> for Signature<LEFT_PLUS_RIGHT_LEN> {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.0[..]
}
}
impl<const LEFT_PLUS_RIGHT_LEN: usize> AsRef<[u8; LEFT_PLUS_RIGHT_LEN]>
for Signature<LEFT_PLUS_RIGHT_LEN>
{
fn as_ref(&self) -> &[u8; LEFT_PLUS_RIGHT_LEN] {
&self.0
}
}
impl<const LEFT_PLUS_RIGHT_LEN: usize> AsRef<[u8]> for Signature<LEFT_PLUS_RIGHT_LEN> {
fn as_ref(&self) -> &[u8] {
&self.0[..]
}
}
pub type Signature<const LEFT_PLUS_RIGHT_LEN: usize, SubTag> =
SignatureBytes<LEFT_PLUS_RIGHT_LEN, (PairedCryptoTag, SubTag)>;
#[cfg(feature = "serde")]
impl<const LEFT_PLUS_RIGHT_LEN: usize> Serialize for Signature<LEFT_PLUS_RIGHT_LEN> {
impl<const LEFT_PLUS_RIGHT_LEN: usize, SubTag> Serialize
for Signature<LEFT_PLUS_RIGHT_LEN, SubTag>
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
@@ -356,28 +266,23 @@ impl<const LEFT_PLUS_RIGHT_LEN: usize> Serialize for Signature<LEFT_PLUS_RIGHT_L
}
#[cfg(feature = "serde")]
impl<'de, const LEFT_PLUS_RIGHT_LEN: usize> Deserialize<'de> for Signature<LEFT_PLUS_RIGHT_LEN> {
impl<'de, const LEFT_PLUS_RIGHT_LEN: usize, SubTag> Deserialize<'de>
for Signature<LEFT_PLUS_RIGHT_LEN, SubTag>
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let bytes = array_bytes::hex2bytes(&String::deserialize(deserializer)?)
.map_err(|e| de::Error::custom(format!("{:?}", e)))?;
Signature::<LEFT_PLUS_RIGHT_LEN>::try_from(bytes.as_ref()).map_err(|e| {
Signature::<LEFT_PLUS_RIGHT_LEN, SubTag>::try_from(bytes.as_ref()).map_err(|e| {
de::Error::custom(format!("Error converting deserialized data into signature: {:?}", e))
})
}
}
impl<const LEFT_PLUS_RIGHT_LEN: usize> From<Signature<LEFT_PLUS_RIGHT_LEN>>
for [u8; LEFT_PLUS_RIGHT_LEN]
{
fn from(signature: Signature<LEFT_PLUS_RIGHT_LEN>) -> [u8; LEFT_PLUS_RIGHT_LEN] {
signature.0
}
}
impl<const LEFT_PLUS_RIGHT_LEN: usize> sp_std::fmt::Debug for Signature<LEFT_PLUS_RIGHT_LEN>
impl<const LEFT_PLUS_RIGHT_LEN: usize, SubTag> sp_std::fmt::Debug
for Signature<LEFT_PLUS_RIGHT_LEN, SubTag>
where
[u8; LEFT_PLUS_RIGHT_LEN]: crate::hexdisplay::AsBytesRef,
{
@@ -392,24 +297,30 @@ where
}
}
impl<const LEFT_PLUS_RIGHT_LEN: usize> UncheckedFrom<[u8; LEFT_PLUS_RIGHT_LEN]>
for Signature<LEFT_PLUS_RIGHT_LEN>
{
fn unchecked_from(data: [u8; LEFT_PLUS_RIGHT_LEN]) -> Self {
Signature(data)
}
}
/// A key pair.
#[derive(Clone)]
pub struct Pair<
LeftPair: PairT,
RightPair: PairT,
const PUBLIC_KEY_LEN: usize,
const SIGNATURE_LEN: usize,
SubTag,
> {
left: LeftPair,
right: RightPair,
_phantom: PhantomData<fn() -> SubTag>,
}
impl<
LeftPair: PairT + Clone,
RightPair: PairT + Clone,
const PUBLIC_KEY_LEN: usize,
const SIGNATURE_LEN: usize,
SubTag,
> Clone for Pair<LeftPair, RightPair, PUBLIC_KEY_LEN, SIGNATURE_LEN, SubTag>
{
fn clone(&self) -> Self {
Self { left: self.left.clone(), right: self.right.clone(), _phantom: PhantomData }
}
}
impl<
@@ -417,18 +328,19 @@ impl<
RightPair: PairT,
const PUBLIC_KEY_LEN: usize,
const SIGNATURE_LEN: usize,
> PairT for Pair<LeftPair, RightPair, PUBLIC_KEY_LEN, SIGNATURE_LEN>
SubTag: PairedCryptoSubTagBound,
> PairT for Pair<LeftPair, RightPair, PUBLIC_KEY_LEN, SIGNATURE_LEN, SubTag>
where
Pair<LeftPair, RightPair, PUBLIC_KEY_LEN, SIGNATURE_LEN>: CryptoType,
Pair<LeftPair, RightPair, PUBLIC_KEY_LEN, SIGNATURE_LEN, SubTag>: CryptoType,
LeftPair::Signature: SignatureBound,
RightPair::Signature: SignatureBound,
Public<PUBLIC_KEY_LEN>: CryptoType,
Public<PUBLIC_KEY_LEN, SubTag>: CryptoType,
LeftPair::Seed: From<Seed> + Into<Seed>,
RightPair::Seed: From<Seed> + Into<Seed>,
{
type Seed = Seed;
type Public = Public<PUBLIC_KEY_LEN>;
type Signature = Signature<SIGNATURE_LEN>;
type Public = Public<PUBLIC_KEY_LEN, SubTag>;
type Signature = Signature<SIGNATURE_LEN, SubTag>;
fn from_seed_slice(seed_slice: &[u8]) -> Result<Self, SecretStringError> {
if seed_slice.len() != SECURE_SEED_LEN {
@@ -436,7 +348,7 @@ where
}
let left = LeftPair::from_seed_slice(&seed_slice)?;
let right = RightPair::from_seed_slice(&seed_slice)?;
Ok(Pair { left, right })
Ok(Pair { left, right, _phantom: PhantomData })
}
/// Derive a child key from a series of given junctions.
@@ -459,7 +371,7 @@ where
_ => None,
};
Ok((Self { left: left.0, right: right.0 }, seed))
Ok((Self { left: left.0, right: right.0, _phantom: PhantomData }, seed))
}
fn public(&self) -> Self::Public {
@@ -479,16 +391,18 @@ where
Self::Signature::unchecked_from(raw)
}
fn verify<M: AsRef<[u8]>>(sig: &Self::Signature, message: M, public: &Self::Public) -> bool {
fn verify<Msg: AsRef<[u8]>>(
sig: &Self::Signature,
message: Msg,
public: &Self::Public,
) -> bool {
let Ok(left_pub) = public.0[..LeftPair::Public::LEN].try_into() else { return false };
let Ok(left_sig) = sig.0[0..LeftPair::Signature::LEN].try_into() else { return false };
if !LeftPair::verify(&left_sig, message.as_ref(), &left_pub) {
return false
}
let Ok(right_pub) = public.0[LeftPair::Public::LEN..PUBLIC_KEY_LEN].try_into() else {
return false
};
let Ok(right_pub) = public.0[LeftPair::Public::LEN..].try_into() else { return false };
let Ok(right_sig) = sig.0[LeftPair::Signature::LEN..].try_into() else { return false };
RightPair::verify(&right_sig, message.as_ref(), &right_pub)
}
@@ -506,6 +420,7 @@ where
mod test {
use super::*;
use crate::{crypto::DEV_PHRASE, KeccakHasher};
use codec::{Decode, Encode};
use ecdsa_bls377::{Pair, Signature};
use crate::{bls377, ecdsa};
+26 -223
View File
@@ -19,6 +19,7 @@
//!
//! Note: `CHAIN_CODE_LENGTH` must be equal to `crate::crypto::JUNCTION_ID_LEN`
//! for this to work.
#[cfg(feature = "serde")]
use crate::crypto::Ss58Codec;
use crate::crypto::{DeriveError, DeriveJunction, Pair as TraitPair, SecretStringError};
@@ -30,20 +31,16 @@ use schnorrkel::{
};
use sp_std::vec::Vec;
use crate::{
crypto::{
ByteArray, CryptoType, CryptoTypeId, Derive, FromEntropy, Public as TraitPublic,
UncheckedFrom,
},
hash::{H256, H512},
use crate::crypto::{
CryptoType, CryptoTypeId, Derive, Public as TraitPublic, PublicBytes, SignatureBytes,
};
use codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
use sp_std::ops::Deref;
use schnorrkel::keys::{MINI_SECRET_KEY_LENGTH, SECRET_KEY_LENGTH};
#[cfg(feature = "serde")]
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
#[cfg(feature = "std")]
use sp_runtime_interface::pass_by::PassByInner;
#[cfg(all(not(feature = "std"), feature = "serde"))]
use sp_std::alloc::{format, string::String};
@@ -54,22 +51,17 @@ const SIGNING_CTX: &[u8] = b"substrate";
/// An identifier used to match public keys against sr25519 keys
pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"sr25");
/// The byte length of public key
pub const PUBLIC_KEY_SERIALIZED_SIZE: usize = 32;
/// The byte length of signature
pub const SIGNATURE_SERIALIZED_SIZE: usize = 64;
#[doc(hidden)]
pub struct Sr25519Tag;
/// An Schnorrkel/Ristretto x25519 ("sr25519") public key.
#[derive(
PartialEq,
Eq,
PartialOrd,
Ord,
Clone,
Copy,
Encode,
Decode,
PassByInner,
MaxEncodedLen,
TypeInfo,
Hash,
)]
pub struct Public(pub [u8; 32]);
pub type Public = PublicBytes<PUBLIC_KEY_SERIALIZED_SIZE, Sr25519Tag>;
/// An Schnorrkel/Ristretto x25519 ("sr25519") key pair.
pub struct Pair(Keypair);
@@ -84,52 +76,6 @@ impl Clone for Pair {
}
}
impl FromEntropy for Public {
fn from_entropy(input: &mut impl codec::Input) -> Result<Self, codec::Error> {
let mut result = Self([0u8; 32]);
input.read(&mut result.0[..])?;
Ok(result)
}
}
impl AsRef<[u8; 32]> for Public {
fn as_ref(&self) -> &[u8; 32] {
&self.0
}
}
impl AsRef<[u8]> for Public {
fn as_ref(&self) -> &[u8] {
&self.0[..]
}
}
impl AsMut<[u8]> for Public {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.0[..]
}
}
impl Deref for Public {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<Public> for [u8; 32] {
fn from(x: Public) -> [u8; 32] {
x.0
}
}
impl From<Public> for H256 {
fn from(x: Public) -> H256 {
x.0.into()
}
}
#[cfg(feature = "std")]
impl std::str::FromStr for Public {
type Err = crate::crypto::PublicError;
@@ -139,31 +85,6 @@ impl std::str::FromStr for Public {
}
}
impl TryFrom<&[u8]> for Public {
type Error = ();
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
if data.len() != Self::LEN {
return Err(())
}
let mut r = [0u8; 32];
r.copy_from_slice(data);
Ok(Self::unchecked_from(r))
}
}
impl UncheckedFrom<[u8; 32]> for Public {
fn unchecked_from(x: [u8; 32]) -> Self {
Public::from_raw(x)
}
}
impl UncheckedFrom<H256> for Public {
fn unchecked_from(x: H256) -> Self {
Public::from_h256(x)
}
}
#[cfg(feature = "std")]
impl std::fmt::Display for Public {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
@@ -175,7 +96,7 @@ impl sp_std::fmt::Debug for Public {
#[cfg(feature = "std")]
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.0), &s[0..8])
write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(self.inner()), &s[0..8])
}
#[cfg(not(feature = "std"))]
@@ -206,22 +127,7 @@ impl<'de> Deserialize<'de> for Public {
}
/// An Schnorrkel/Ristretto x25519 ("sr25519") signature.
#[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq, Hash)]
pub struct Signature(pub [u8; 64]);
impl TryFrom<&[u8]> for Signature {
type Error = ();
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
if data.len() == 64 {
let mut inner = [0u8; 64];
inner.copy_from_slice(data);
Ok(Signature(inner))
} else {
Err(())
}
}
}
pub type Signature = SignatureBytes<SIGNATURE_SERIALIZED_SIZE, Sr25519Tag>;
#[cfg(feature = "serde")]
impl Serialize for Signature {
@@ -246,48 +152,10 @@ impl<'de> Deserialize<'de> for Signature {
}
}
impl Clone for Signature {
fn clone(&self) -> Self {
let mut r = [0u8; 64];
r.copy_from_slice(&self.0[..]);
Signature(r)
}
}
impl From<Signature> for [u8; 64] {
fn from(v: Signature) -> [u8; 64] {
v.0
}
}
impl From<Signature> for H512 {
fn from(v: Signature) -> H512 {
H512::from(v.0)
}
}
impl AsRef<[u8; 64]> for Signature {
fn as_ref(&self) -> &[u8; 64] {
&self.0
}
}
impl AsRef<[u8]> for Signature {
fn as_ref(&self) -> &[u8] {
&self.0[..]
}
}
impl AsMut<[u8]> for Signature {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.0[..]
}
}
#[cfg(feature = "full_crypto")]
impl From<schnorrkel::Signature> for Signature {
fn from(s: schnorrkel::Signature) -> Signature {
Signature(s.to_bytes())
Signature::from(s.to_bytes())
}
}
@@ -303,45 +171,6 @@ impl sp_std::fmt::Debug for Signature {
}
}
impl UncheckedFrom<[u8; 64]> for Signature {
fn unchecked_from(data: [u8; 64]) -> Signature {
Signature(data)
}
}
impl Signature {
/// A new instance from the given 64-byte `data`.
///
/// 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, or if you
/// immediately verify the signature. All functions that verify signatures
/// will fail if the `Signature` is not actually a valid signature.
pub fn from_raw(data: [u8; 64]) -> Signature {
Signature(data)
}
/// A new instance from the given slice that should be 64 bytes long.
///
/// 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() != 64 {
return None
}
let mut r = [0u8; 64];
r.copy_from_slice(data);
Some(Signature(r))
}
/// A new instance from an H512.
///
/// 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_h512(v: H512) -> Signature {
Signature(v.into())
}
}
impl Derive for Public {
/// Derive a child key from a series of given junctions.
///
@@ -355,37 +184,10 @@ impl Derive for Public {
DeriveJunction::Hard(_cc) => return None,
}
}
Some(Self(acc.to_bytes()))
Some(Self::from(acc.to_bytes()))
}
}
impl Public {
/// A new instance from the given 32-byte `data`.
///
/// 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; 32]) -> Self {
Public(data)
}
/// A new instance from an H256.
///
/// 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_h256(x: H256) -> Self {
Public(x.into())
}
/// Return a slice filled with raw data.
pub fn as_array_ref(&self) -> &[u8; 32] {
self.as_ref()
}
}
impl ByteArray for Public {
const LEN: usize = 32;
}
impl TraitPublic for Public {}
#[cfg(feature = "std")]
@@ -438,9 +240,7 @@ impl TraitPair for Pair {
/// Get the public key.
fn public(&self) -> Public {
let mut pk = [0u8; 32];
pk.copy_from_slice(&self.0.public.to_bytes());
Public(pk)
Public::from(self.0.public.to_bytes())
}
/// Make a new key pair from raw secret seed material.
@@ -720,7 +520,7 @@ pub mod vrf {
impl VrfPublic for Public {
fn vrf_verify(&self, data: &Self::VrfSignData, signature: &Self::VrfSignature) -> bool {
let do_verify = || {
let public = schnorrkel::PublicKey::from_bytes(self)?;
let public = schnorrkel::PublicKey::from_bytes(&self.0)?;
let inout =
signature.pre_output.0.attach_input_hash(&public, data.transcript.0.clone())?;
@@ -820,7 +620,10 @@ pub mod vrf {
#[cfg(test)]
mod tests {
use super::{vrf::*, *};
use crate::crypto::{Ss58Codec, VrfPublic, VrfSecret, DEV_ADDRESS, DEV_PHRASE};
use crate::{
crypto::{Ss58Codec, VrfPublic, VrfSecret, DEV_ADDRESS, DEV_PHRASE},
ByteArray as _,
};
use serde_json;
#[test]
@@ -984,10 +787,10 @@ mod tests {
let (pair, _) = Pair::generate();
let public = pair.public();
let message = b"Signed payload";
let Signature(mut bytes) = pair.sign(&message[..]);
let mut signature = pair.sign(&message[..]);
let bytes = &mut signature.0;
bytes[0] = !bytes[0];
bytes[2] = !bytes[2];
let signature = Signature(bytes);
assert!(!Pair::verify(&signature, &message[..], &public));
}
+1 -1
View File
@@ -528,7 +528,7 @@ mod tests {
assert!(res.is_some());
// does not verify with default out-of-the-box verification
assert!(!ecdsa_bls377::Pair::verify(&res.clone().unwrap(), &msg[..], &pair.public()));
assert!(!ecdsa_bls377::Pair::verify(&res.unwrap(), &msg[..], &pair.public()));
// should verify using keccak256 as hasher
assert!(ecdsa_bls377::Pair::verify_with_hasher::<KeccakHasher>(
+1 -1
View File
@@ -133,7 +133,7 @@ impl Verify for sp_core::ecdsa::Signature {
self.as_ref(),
&sp_io::hashing::blake2_256(msg.get()),
) {
Ok(pubkey) => signer.as_ref() == &pubkey[..],
Ok(pubkey) => signer.0 == pubkey,
_ => false,
}
}
@@ -340,8 +340,8 @@ impl Statement {
Some(Proof::OnChain { .. }) | None => SignatureVerificationResult::NoSignature,
Some(Proof::Sr25519 { signature, signer }) => {
let to_sign = self.signature_material();
let signature = sp_core::sr25519::Signature(*signature);
let public = sp_core::sr25519::Public(*signer);
let signature = sp_core::sr25519::Signature::from(*signature);
let public = sp_core::sr25519::Public::from(*signer);
if signature.verify(to_sign.as_slice(), &public) {
SignatureVerificationResult::Valid(*signer)
} else {
@@ -350,8 +350,8 @@ impl Statement {
},
Some(Proof::Ed25519 { signature, signer }) => {
let to_sign = self.signature_material();
let signature = sp_core::ed25519::Signature(*signature);
let public = sp_core::ed25519::Public(*signer);
let signature = sp_core::ed25519::Signature::from(*signature);
let public = sp_core::ed25519::Public::from(*signer);
if signature.verify(to_sign.as_slice(), &public) {
SignatureVerificationResult::Valid(*signer)
} else {
@@ -360,8 +360,8 @@ impl Statement {
},
Some(Proof::Secp256k1Ecdsa { signature, signer }) => {
let to_sign = self.signature_material();
let signature = sp_core::ecdsa::Signature(*signature);
let public = sp_core::ecdsa::Public(*signer);
let signature = sp_core::ecdsa::Signature::from(*signature);
let public = sp_core::ecdsa::Public::from(*signer);
if signature.verify(to_sign.as_slice(), &public) {
let sender_hash =
<sp_runtime::traits::BlakeTwo256 as sp_core::Hasher>::hash(signer);