blueprint_crypto_sp_core/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2
3#[cfg(feature = "bls")]
4mod bls;
5#[cfg(feature = "bls")]
6pub use bls::*;
7
8#[cfg(feature = "aggregation")]
9mod aggregation;
10
11pub mod error;
12
13#[cfg(test)]
14mod tests;
15
16use blueprint_crypto_core::BytesEncoding;
17use blueprint_std::{string::String, vec::Vec};
18use sp_core::{ByteArray, Pair};
19
20/// Implements serde and KeyType trait for any sp_core crypto type.
21///
22/// Implements common functionality for key pairs and public keys.
23macro_rules! impl_sp_core_pair_public {
24    ($key_type:ident, $pair_type:ty, $public:ty) => {
25        paste::paste! {
26            /// Wrapper struct for the cryptographic key pair.
27            ///
28            /// This provides a safe interface for serialization and deserialization
29            /// of the underlying key pair type.
30            #[derive(Clone)]
31            pub struct [<Sp $key_type Pair>](pub $pair_type);
32
33            impl PartialEq for [<Sp $key_type Pair>] {
34                fn eq(&self, other: &Self) -> bool {
35                    self.to_bytes() == other.to_bytes()
36                }
37            }
38
39            impl Eq for [<Sp $key_type Pair>] {}
40
41            impl PartialOrd for [<Sp $key_type Pair>] {
42                fn partial_cmp(&self, other: &Self) -> Option<blueprint_std::cmp::Ordering> {
43                    Some(self.cmp(other))
44                }
45            }
46
47            impl Ord for [<Sp $key_type Pair>] {
48                fn cmp(&self, other: &Self) -> blueprint_std::cmp::Ordering {
49                    self.to_bytes().cmp(&other.to_bytes())
50                }
51            }
52
53            impl blueprint_std::fmt::Debug for [<Sp $key_type Pair>] {
54                fn fmt(&self, f: &mut blueprint_std::fmt::Formatter<'_>) -> blueprint_std::fmt::Result {
55                    write!(f, "{:?}", self.to_bytes())
56                }
57            }
58
59            impl serde::Serialize for [<Sp $key_type Pair>] {
60                fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
61                where
62                    S: serde::Serializer,
63                {
64                    <Vec::<u8>>::serialize(&self.to_bytes(), serializer)
65                }
66            }
67
68            impl<'de> serde::Deserialize<'de> for [<Sp $key_type Pair>] {
69                fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
70                where
71                    D: serde::Deserializer<'de>,
72                {
73                    let seed = <Vec::<u8>>::deserialize(deserializer)?;
74                    let pair = <$pair_type>::from_seed_slice(&seed).map_err(|_| serde::de::Error::custom("Invalid seed length"))?;
75                    Ok([<Sp $key_type Pair>](pair))
76                }
77            }
78
79            /// Wrapper struct for the cryptographic public key.
80            #[derive(Clone, serde::Serialize, serde::Deserialize)]
81            pub struct [<Sp $key_type Public>](pub <$pair_type as sp_core::Pair>::Public);
82
83            impl blueprint_std::hash::Hash for [<Sp $key_type Public>] {
84                fn hash<H: blueprint_std::hash::Hasher>(&self, state: &mut H) {
85                    self.0.to_raw_vec().hash(state);
86                }
87            }
88
89            impl BytesEncoding for [<Sp $key_type Public>] {
90                fn to_bytes(&self) -> Vec<u8> {
91                    self.0.to_raw_vec()
92                }
93
94                fn from_bytes(bytes: &[u8]) -> core::result::Result<Self, serde::de::value::Error> {
95                    Self::from_bytes_impl(bytes)
96                }
97            }
98
99            impl PartialEq for [<Sp $key_type Public>]{
100                fn eq(&self, other: &Self) -> bool {
101                    self.0 == other.0
102                }
103            }
104
105            impl Eq for [<Sp $key_type Public>]{}
106
107            impl PartialOrd for [<Sp $key_type Public>]{
108                fn partial_cmp(&self, other: &Self) -> Option<blueprint_std::cmp::Ordering> {
109                    Some(self.cmp(other))
110                }
111            }
112
113            impl Ord for [<Sp $key_type Public>]{
114                fn cmp(&self, other: &Self) -> blueprint_std::cmp::Ordering {
115                    self.to_bytes().cmp(&other.to_bytes())
116                }
117            }
118
119            impl blueprint_std::fmt::Debug for [<Sp $key_type Public>]{
120                fn fmt(&self, f: &mut blueprint_std::fmt::Formatter<'_>) -> blueprint_std::fmt::Result {
121                    write!(f, "{:?}", self.to_bytes())
122                }
123            }
124
125            impl blueprint_std::fmt::Display for [<Sp $key_type Public>] {
126                fn fmt(&self, f: &mut blueprint_std::fmt::Formatter<'_>) -> blueprint_std::fmt::Result {
127                    write!(f, "{}", hex::encode(self.to_bytes()))
128                }
129            }
130        }
131    };
132}
133
134/// Implements signature functionality for non-BLS signatures.
135macro_rules! impl_sp_core_signature {
136    ($key_type:ident, $pair_type:ty) => {
137        paste::paste! {
138            #[derive(Default, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
139            pub struct [<Sp $key_type Signature>](pub <$pair_type as sp_core::Pair>::Signature);
140
141            impl PartialOrd for [<Sp $key_type Signature>] {
142                fn partial_cmp(&self, other: &Self) -> Option<blueprint_std::cmp::Ordering> {
143                    Some(self.cmp(other))
144                }
145            }
146
147            impl Ord for [<Sp $key_type Signature>] {
148                fn cmp(&self, other: &Self) -> blueprint_std::cmp::Ordering {
149                    self.0.0.cmp(&other.0.0)
150                }
151            }
152
153            impl blueprint_std::fmt::Debug for [<Sp $key_type Signature>] {
154                fn fmt(&self, f: &mut blueprint_std::fmt::Formatter<'_>) -> blueprint_std::fmt::Result {
155                    write!(f, "{:?}", self.0.0)
156                }
157            }
158
159            impl blueprint_std::fmt::Display for [<Sp $key_type Signature>] {
160                fn fmt(&self, f: &mut blueprint_std::fmt::Formatter<'_>) -> blueprint_std::fmt::Result {
161                    write!(f, "{}", hex::encode(self.0.0))
162                }
163            }
164
165            impl BytesEncoding for [<Sp $key_type Signature>] {
166                fn to_bytes(&self) -> Vec<u8> {
167                    self.0.to_raw_vec()
168                }
169
170                fn from_bytes(bytes: &[u8]) -> core::result::Result<Self, serde::de::value::Error> {
171                    match <$pair_type as sp_core::Pair>::Signature::from_slice(bytes) {
172                        Ok(sig) => Ok([<Sp $key_type Signature>](sig)),
173                        Err(_) => Err(serde::de::Error::custom("Invalid signature length")),
174                    }
175                }
176            }
177        }
178    };
179}
180
181/// Implements KeyType trait for non-BLS signatures.
182macro_rules! impl_sp_core_key_type {
183    ($key_type:ident, $pair_type:ty) => {
184        paste::paste! {
185            #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize)]
186            pub struct [<Sp $key_type>];
187
188            impl blueprint_crypto_core::KeyType for [<Sp $key_type>] {
189                type Public = [<Sp $key_type Public>];
190                type Secret = [<Sp $key_type Pair>];
191                type Signature = [<Sp $key_type Signature>];
192                type Error = $crate::error::SpCoreError;
193
194                fn key_type_id() -> blueprint_crypto_core::KeyTypeId {
195                    blueprint_crypto_core::KeyTypeId::$key_type
196                }
197
198                fn generate_with_seed(seed: Option<&[u8]>) -> $crate::error::Result<Self::Secret> {
199                    match seed {
200                        Some(seed) => {
201                            if seed.len() != 32 {
202                                return Err($crate::error::SpCoreError::InvalidSeed("Invalid seed length".into()));
203                            }
204                            let seed_array: [u8; 32] = seed.try_into()
205                                .map_err(|_| $crate::error::SpCoreError::InvalidSeed("Invalid seed length".into()))?;
206                            let pair = <$pair_type>::from_seed(&seed_array);
207                            Ok([<Sp $key_type Pair>](pair))
208                        }
209                        None => {
210                            #[cfg(feature = "std")]
211                            let (pair, _) = <$pair_type>::generate();
212                            #[cfg(not(feature = "std"))]
213                            let pair = {
214                                use blueprint_std::Rng;
215                                let seed = Self::get_test_rng().r#gen::<[u8; 32]>();
216                                <$pair_type>::from_seed(&seed)
217                            };
218                            Ok([<Sp $key_type Pair>](pair))
219                        }
220                    }
221                }
222
223                fn generate_with_string(secret: String) -> $crate::error::Result<Self::Secret> {
224                    // For now, treat the string as a hex-encoded seed
225                    let seed = hex::decode(&secret)
226                        .map_err(|_| $crate::error::SpCoreError::InvalidSeed("Invalid hex string".into()))?;
227                    if seed.len() != 32 {
228                        return Err($crate::error::SpCoreError::InvalidSeed("Invalid seed length".into()));
229                    }
230                    let seed_array: [u8; 32] = seed.try_into()
231                        .map_err(|_| $crate::error::SpCoreError::InvalidSeed("Invalid seed length".into()))?;
232                    let pair = <$pair_type>::from_seed(&seed_array);
233                    Ok([<Sp $key_type Pair>](pair))
234                }
235
236                fn public_from_secret(secret: &Self::Secret) -> Self::Public {
237                    [<Sp $key_type Public>](secret.0.public())
238                }
239
240                fn sign_with_secret(
241                    secret: &mut Self::Secret,
242                    msg: &[u8],
243                ) -> $crate::error::Result<Self::Signature> {
244                    Ok([<Sp $key_type Signature>](secret.0.sign(msg)))
245                }
246
247                fn sign_with_secret_pre_hashed(
248                    secret: &mut Self::Secret,
249                    msg: &[u8; 32],
250                ) -> $crate::error::Result<Self::Signature> {
251                    Ok([<Sp $key_type Signature>](secret.0.sign(msg)))
252                }
253
254                fn verify(public: &Self::Public, msg: &[u8], signature: &Self::Signature) -> bool {
255                    <$pair_type as sp_core::Pair>::verify(&signature.0, msg, &public.0)
256                }
257            }
258
259            impl [<Sp $key_type Pair>] {
260                pub fn public(&self) -> [<Sp $key_type Public>] {
261                    [<Sp $key_type Public>](self.0.public())
262                }
263            }
264
265            impl BytesEncoding for [<Sp $key_type Pair>] {
266                fn to_bytes(&self) -> Vec<u8> {
267                    self.0.to_raw_vec()
268                }
269
270                fn from_bytes(bytes: &[u8]) -> core::result::Result<Self, serde::de::value::Error> {
271                    let inner = <$pair_type>::from_seed_slice(bytes).map_err(|_| serde::de::Error::custom("Invalid seed length"))?;
272                    Ok(Self(inner))
273                }
274            }
275
276            impl blueprint_std::ops::Deref for [<Sp $key_type Pair>] {
277                type Target = $pair_type;
278
279                fn deref(&self) -> &Self::Target {
280                    &self.0
281                }
282            }
283
284            impl blueprint_std::ops::DerefMut for [<Sp $key_type Pair>] {
285                fn deref_mut(&mut self) -> &mut Self::Target {
286                    &mut self.0
287                }
288            }
289        }
290    };
291}
292
293/// Implements both pair/public and signature traits for a given sp_core crypto type
294macro_rules! impl_sp_core_crypto {
295    ($key_type:ident, $module:ident) => {
296        impl_sp_core_pair_public!($key_type, sp_core::$module::Pair, sp_core::$module::Public);
297        impl_sp_core_signature!($key_type, sp_core::$module::Pair);
298        impl_sp_core_key_type!($key_type, sp_core::$module::Pair);
299    };
300}
301
302impl_sp_core_crypto!(Ecdsa, ecdsa);
303
304impl SpEcdsaPublic {
305    fn from_bytes_impl(bytes: &[u8]) -> Result<Self, serde::de::value::Error> {
306        let inner = <sp_core::ecdsa::Pair as sp_core::Pair>::Public::from_full(bytes)
307            .map_err(|_| serde::de::Error::custom("Invalid public key length"))?;
308        Ok(Self(inner))
309    }
310}
311
312impl_sp_core_crypto!(Ed25519, ed25519);
313
314impl SpEd25519Public {
315    fn from_bytes_impl(bytes: &[u8]) -> Result<Self, serde::de::value::Error> {
316        let inner = <sp_core::ed25519::Pair as sp_core::Pair>::Public::from_slice(bytes)
317            .map_err(|_| serde::de::Error::custom("Invalid public key length"))?;
318        Ok(Self(inner))
319    }
320}
321
322impl_sp_core_crypto!(Sr25519, sr25519);
323
324impl SpSr25519Public {
325    fn from_bytes_impl(bytes: &[u8]) -> Result<Self, serde::de::value::Error> {
326        let inner = <sp_core::sr25519::Pair as sp_core::Pair>::Public::from_slice(bytes)
327            .map_err(|_| serde::de::Error::custom("Invalid public key length"))?;
328        Ok(Self(inner))
329    }
330}
331
332impl Copy for SpEcdsaPublic {}
333impl Copy for SpEd25519Public {}
334impl Copy for SpSr25519Public {}