1#![cfg_attr(not(feature = "std"), no_std)]
2
3use blueprint_std::fmt::Debug;
4use blueprint_std::hash::Hash;
5use blueprint_std::string::String;
6use blueprint_std::vec::Vec;
7use serde::{Deserialize, Serialize, de::DeserializeOwned};
8
9pub mod aggregation;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
12pub enum KeyTypeId {
13 #[cfg(feature = "bn254")]
14 Bn254,
15 #[cfg(any(feature = "k256", feature = "tangle"))]
16 Ecdsa,
17 #[cfg(any(feature = "sr25519-schnorrkel", feature = "tangle"))]
18 Sr25519,
19 #[cfg(any(feature = "bls", feature = "tangle"))]
20 Bls381,
21 #[cfg(any(feature = "bls", feature = "tangle"))]
22 Bls377,
23 #[cfg(any(feature = "zebra", feature = "tangle"))]
24 Ed25519,
25}
26
27impl KeyTypeId {
28 pub const ENABLED: &'static [Self] = &[
29 #[cfg(feature = "bn254")]
30 Self::Bn254,
31 #[cfg(any(feature = "k256", feature = "tangle"))]
32 Self::Ecdsa,
33 #[cfg(any(feature = "sr25519-schnorrkel", feature = "tangle"))]
34 Self::Sr25519,
35 #[cfg(any(feature = "bls", feature = "tangle"))]
36 Self::Bls381,
37 #[cfg(any(feature = "bls", feature = "tangle"))]
38 Self::Bls377,
39 #[cfg(any(feature = "zebra", feature = "tangle"))]
40 Self::Ed25519,
41 ];
42
43 pub fn name(&self) -> &'static str {
44 match *self {
45 #[cfg(feature = "bn254")]
46 Self::Bn254 => "bn254",
47 #[cfg(any(feature = "k256", feature = "tangle"))]
48 Self::Ecdsa => "ecdsa",
49 #[cfg(any(feature = "sr25519-schnorrkel", feature = "tangle"))]
50 Self::Sr25519 => "sr25519",
51 #[cfg(any(feature = "bls", feature = "tangle"))]
52 Self::Bls381 => "bls381",
53 #[cfg(any(feature = "bls", feature = "tangle"))]
54 Self::Bls377 => "bls377",
55 #[cfg(any(feature = "zebra", feature = "tangle"))]
56 Self::Ed25519 => "ed25519",
57 #[cfg(all(
58 not(feature = "bn254"),
59 not(feature = "k256"),
60 not(feature = "sr25519-schnorrkel"),
61 not(feature = "bls"),
62 not(feature = "zebra"),
63 not(feature = "tangle")
64 ))]
65 _ => unreachable!("All possible variants are feature-gated"),
66 }
67 }
68}
69
70pub trait BytesEncoding: Sized {
71 fn to_bytes(&self) -> Vec<u8>;
72 fn from_bytes(bytes: &[u8]) -> Result<Self, serde::de::value::Error>;
73}
74
75pub trait KeyType:
77 Clone
78 + Eq
79 + Debug
80 + PartialEq
81 + Ord
82 + PartialOrd
83 + Hash
84 + Sized
85 + Send
86 + Sync
87 + Serialize
88 + DeserializeOwned
89 + 'static
90{
91 type Secret: Clone
92 + Serialize
93 + DeserializeOwned
94 + Ord
95 + Send
96 + Sync
97 + Eq
98 + PartialEq
99 + BytesEncoding
100 + Debug;
101 type Public: Clone
102 + Serialize
103 + DeserializeOwned
104 + Ord
105 + Send
106 + Sync
107 + Hash
108 + Eq
109 + PartialEq
110 + BytesEncoding
111 + Debug;
112
113 type Signature: Clone
114 + Serialize
115 + DeserializeOwned
116 + Ord
117 + Send
118 + Sync
119 + Eq
120 + PartialEq
121 + BytesEncoding
122 + Debug;
123 type Error: Clone + Send + Sync + Debug;
124
125 fn key_type_id() -> KeyTypeId;
126
127 #[cfg(feature = "std")]
129 fn get_rng() -> impl blueprint_std::CryptoRng + blueprint_std::Rng {
130 blueprint_std::rand::thread_rng()
131 }
132
133 #[cfg(not(feature = "std"))]
134 fn get_rng() -> impl blueprint_std::CryptoRng + blueprint_std::Rng {
135 blueprint_std::test_rng()
136 }
137
138 fn get_test_rng() -> impl blueprint_std::CryptoRng + blueprint_std::Rng {
140 blueprint_std::test_rng()
141 }
142
143 fn generate_with_seed(seed: Option<&[u8]>) -> Result<Self::Secret, Self::Error>;
144 fn generate_with_string(secret: String) -> Result<Self::Secret, Self::Error>;
145 fn public_from_secret(secret: &Self::Secret) -> Self::Public;
146 fn sign_with_secret(
147 secret: &mut Self::Secret,
148 msg: &[u8],
149 ) -> Result<Self::Signature, Self::Error>;
150 fn sign_with_secret_pre_hashed(
151 secret: &mut Self::Secret,
152 msg: &[u8; 32],
153 ) -> Result<Self::Signature, Self::Error>;
154 fn verify(public: &Self::Public, msg: &[u8], signature: &Self::Signature) -> bool;
155}
156
157#[cfg(feature = "clap")]
158impl clap::ValueEnum for KeyTypeId {
159 fn value_variants<'a>() -> &'a [Self] {
160 &[
161 Self::Sr25519,
162 Self::Ed25519,
163 Self::Ecdsa,
164 Self::Bls381,
165 Self::Bn254,
166 ]
167 }
168
169 fn to_possible_value(&self) -> Option<clap::builder::PossibleValue> {
170 Some(match self {
171 Self::Sr25519 => {
172 clap::builder::PossibleValue::new("sr25519").help("Schnorrkel/Ristretto x25519")
173 }
174 Self::Ed25519 => {
175 clap::builder::PossibleValue::new("ed25519").help("Edwards Curve 25519")
176 }
177 Self::Ecdsa => clap::builder::PossibleValue::new("ecdsa")
178 .help("Elliptic Curve Digital Signature Algorithm"),
179 Self::Bls381 => {
180 clap::builder::PossibleValue::new("bls381").help("Boneh-Lynn-Shacham on BLS12-381")
181 }
182 Self::Bn254 => {
183 clap::builder::PossibleValue::new("blsbn254").help("Boneh-Lynn-Shacham on BN254")
184 }
185 _ => return None,
186 })
187 }
188}
189
190#[macro_export]
191macro_rules! impl_crypto_tests {
192 ($crypto_type:ty, $signing_key:ty, $signature:ty) => {
193 use $crate::KeyType;
194 #[test]
195 fn test_key_generation() {
196 let secret = <$crypto_type>::generate_with_seed(None).unwrap();
198 let _public = <$crypto_type>::public_from_secret(&secret);
199 }
200
201 #[test]
202 fn test_signing_and_verification() {
203 let mut secret = <$crypto_type>::generate_with_seed(None).unwrap();
204 let public = <$crypto_type>::public_from_secret(&secret);
205
206 let message = b"Hello, world!";
208 let signature = <$crypto_type>::sign_with_secret(&mut secret, message).unwrap();
209 assert!(
210 <$crypto_type>::verify(&public, message, &signature),
211 "Signature verification failed"
212 );
213
214 let hashed_msg = [42u8; 32];
216 let signature =
217 <$crypto_type>::sign_with_secret_pre_hashed(&mut secret, &hashed_msg).unwrap();
218
219 let wrong_message = b"Wrong message";
221 assert!(
222 !<$crypto_type>::verify(&public, wrong_message, &signature),
223 "Verification should fail with wrong message"
224 );
225 }
226
227 #[test]
228 fn test_key_serialization() {
229 let secret = <$crypto_type>::generate_with_seed(None).unwrap();
230 let public = <$crypto_type>::public_from_secret(&secret);
231
232 let serialized = serde_json::to_string(&secret).unwrap();
234 let deserialized: $signing_key = serde_json::from_str(&serialized).unwrap();
235 assert_eq!(
236 secret, deserialized,
237 "SigningKey serialization roundtrip failed"
238 );
239
240 let serialized = serde_json::to_string(&public).unwrap();
242 let deserialized = serde_json::from_str(&serialized).unwrap();
243 assert_eq!(
244 public, deserialized,
245 "VerifyingKey serialization roundtrip failed"
246 );
247 }
248
249 #[test]
250 fn test_signature_serialization() {
251 let mut secret = <$crypto_type>::generate_with_seed(None).unwrap();
252 let message = b"Test message";
253 let signature = <$crypto_type>::sign_with_secret(&mut secret, message).unwrap();
254
255 let serialized = serde_json::to_string(&signature).unwrap();
257 let deserialized: $signature = serde_json::from_str(&serialized).unwrap();
258 assert_eq!(
259 signature, deserialized,
260 "Signature serialization roundtrip failed"
261 );
262 }
263
264 #[test]
265 fn test_key_comparison() {
266 let secret1 = <$crypto_type>::generate_with_seed(None).unwrap();
267 let secret2 = <$crypto_type>::generate_with_seed(None).unwrap();
268 let public1 = <$crypto_type>::public_from_secret(&secret1);
269 let public2 = <$crypto_type>::public_from_secret(&secret2);
270
271 assert!(public1 != public2, "Different keys should not be equal");
273 assert_eq!(public1.cmp(&public1), blueprint_std::cmp::Ordering::Equal);
274
275 assert_eq!(public1.partial_cmp(&public2), Some(public1.cmp(&public2)));
277 }
278 };
279}