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