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