blueprint_crypto_sr25519/
lib.rs1#![cfg_attr(not(feature = "std"), no_std)]
2
3pub mod error;
4use error::{Result, Sr25519Error};
5
6#[cfg(test)]
7mod tests;
8
9use blueprint_crypto_core::BytesEncoding;
10use blueprint_crypto_core::{KeyType, KeyTypeId};
11use blueprint_std::{
12 hash::Hash,
13 string::{String, ToString},
14 vec::Vec,
15};
16use schnorrkel::MiniSecretKey;
17
18#[derive(
20 Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize,
21)]
22pub struct SchnorrkelSr25519;
23
24macro_rules! impl_schnorrkel_serde {
25 ($name:ident, $inner:ty) => {
26 #[derive(Clone, PartialEq, Eq, Debug)]
27 pub struct $name(pub $inner);
28
29 impl PartialOrd for $name {
30 fn partial_cmp(&self, other: &Self) -> Option<blueprint_std::cmp::Ordering> {
31 Some(self.cmp(other))
32 }
33 }
34
35 impl Ord for $name {
36 fn cmp(&self, other: &Self) -> blueprint_std::cmp::Ordering {
37 self.0.to_bytes().cmp(&other.0.to_bytes())
38 }
39 }
40
41 impl Hash for $name {
42 fn hash<H: blueprint_std::hash::Hasher>(&self, state: &mut H) {
43 self.0.to_bytes().hash(state);
44 }
45 }
46
47 impl BytesEncoding for $name {
48 fn to_bytes(&self) -> Vec<u8> {
49 self.0.to_bytes().to_vec()
50 }
51
52 fn from_bytes(bytes: &[u8]) -> core::result::Result<Self, serde::de::value::Error> {
53 <$inner>::from_bytes(bytes)
54 .map(Self)
55 .map_err(|e| serde::de::Error::custom(e.to_string()))
56 }
57 }
58
59 impl serde::Serialize for $name {
60 fn serialize<S: serde::Serializer>(
61 &self,
62 serializer: S,
63 ) -> core::result::Result<S::Ok, S::Error> {
64 <Vec<u8>>::serialize(&self.to_bytes(), serializer)
65 }
66 }
67
68 impl<'de> serde::Deserialize<'de> for $name {
69 fn deserialize<D: serde::Deserializer<'de>>(
70 deserializer: D,
71 ) -> core::result::Result<Self, D::Error> {
72 let bytes = <Vec<u8>>::deserialize(deserializer)?;
73 let inner = <$inner>::from_bytes(&bytes)
74 .map_err(|e| serde::de::Error::custom(e.to_string()))?;
75 Ok($name(inner))
76 }
77 }
78 };
79}
80
81impl_schnorrkel_serde!(SchnorrkelPublic, schnorrkel::PublicKey);
82impl_schnorrkel_serde!(SchnorrkelSecret, schnorrkel::SecretKey);
83impl_schnorrkel_serde!(SchnorrkelSignature, schnorrkel::Signature);
84
85impl zeroize::Zeroize for SchnorrkelSecret {
86 fn zeroize(&mut self) {
87 let ptr = (&raw mut self.0).cast::<u8>();
88 let len = core::mem::size_of::<schnorrkel::SecretKey>();
89 unsafe { core::ptr::write_bytes(ptr, 0, len) };
90 core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
91 }
92}
93
94impl Drop for SchnorrkelSecret {
95 fn drop(&mut self) {
96 use zeroize::Zeroize;
97 self.zeroize();
98 }
99}
100
101impl KeyType for SchnorrkelSr25519 {
102 type Secret = SchnorrkelSecret;
103 type Public = SchnorrkelPublic;
104 type Signature = SchnorrkelSignature;
105 type Error = Sr25519Error;
106
107 fn key_type_id() -> KeyTypeId {
108 KeyTypeId::Sr25519
109 }
110
111 fn generate_with_seed(seed: Option<&[u8]>) -> Result<Self::Secret> {
112 let secret_key = if let Some(seed) = seed {
113 if seed.len() > 64 {
115 return Err(Sr25519Error::InvalidSeed(
116 "Seed must not exceed 64 bytes".into(),
117 ));
118 }
119 let mut padded_seed = [0u8; 64];
120 padded_seed[..seed.len()].copy_from_slice(seed);
121 schnorrkel::SecretKey::from_bytes(&padded_seed)
122 .map_err(|e| Sr25519Error::InvalidSeed(e.to_string()))
123 } else {
124 #[cfg(feature = "std")]
125 {
126 let mut rng = Self::get_rng();
127 let mini_secret_key = MiniSecretKey::generate_with(&mut rng);
128 Ok(mini_secret_key.expand(MiniSecretKey::UNIFORM_MODE))
129 }
130 #[cfg(not(feature = "std"))]
131 return Err(Sr25519Error::InvalidSeed(
132 "Random key generation requires the std feature".into(),
133 ));
134 };
135
136 secret_key.map(SchnorrkelSecret)
137 }
138
139 fn generate_with_string(secret: String) -> Result<Self::Secret> {
140 let hex_encoded = hex::decode(secret)?;
141 let secret_key = schnorrkel::SecretKey::from_bytes(&hex_encoded)
142 .map_err(|e| Sr25519Error::InvalidSeed(e.to_string()))?;
143 Ok(SchnorrkelSecret(secret_key))
144 }
145
146 fn public_from_secret(secret: &Self::Secret) -> Self::Public {
147 SchnorrkelPublic(secret.0.to_public())
148 }
149
150 fn sign_with_secret(secret: &mut Self::Secret, msg: &[u8]) -> Result<Self::Signature> {
151 let ctx = schnorrkel::signing_context(b"tangle").bytes(msg);
152 Ok(SchnorrkelSignature(
153 secret.0.sign(ctx, &secret.0.to_public()),
154 ))
155 }
156
157 fn sign_with_secret_pre_hashed(
158 secret: &mut Self::Secret,
159 msg: &[u8; 32],
160 ) -> Result<Self::Signature> {
161 let ctx = schnorrkel::signing_context(b"tangle").bytes(msg);
162 Ok(SchnorrkelSignature(
163 secret.0.sign(ctx, &secret.0.to_public()),
164 ))
165 }
166
167 fn verify(public: &Self::Public, msg: &[u8], signature: &Self::Signature) -> bool {
168 let ctx = schnorrkel::signing_context(b"tangle").bytes(msg);
169 public.0.verify(ctx, &signature.0).is_ok()
170 }
171}