vrf_wasm/traits.rs
1// Copyright (c) 2021, Facebook, Inc. and its affiliates
2// Copyright (c) 2022, Mysten Labs, Inc.
3// SPDX-License-Identifier: Apache-2.0
4
5use rand_core::{CryptoRng, RngCore};
6use serde::{de::DeserializeOwned, Serialize};
7use std::{
8 borrow::Borrow,
9 fmt::{Debug, Display},
10 str::FromStr,
11};
12use crate::error::FastCryptoResult;
13use crate::{
14 encoding::{Base64, Encoding},
15 error::FastCryptoError,
16 hash::HashFunction,
17};
18// Import RNG implementations from the rng module
19pub use crate::rng::{WasmRng, WasmRngFromSeed};
20
21/// Trait impl'd by concrete types that represent digital cryptographic material
22/// (keys).
23///
24/// Key types *must* (as mandated by the `AsRef<[u8]>` bound) be a thin
25/// wrapper around the "bag-of-bytes" serialized form of a key which can
26/// be directly parsed from or written to the "wire".
27///
28/// The [`ToFromBytes`] trait aims to provide similar simplicity by minimizing
29/// the number of steps involved to obtain a serializable key and
30/// ideally ensuring there is one signature type for any given signature system
31/// shared by all "provider" crates.
32///
33/// For signature systems which require a more advanced internal representation
34/// (e.g. involving decoded scalars or decompressed elliptic curve points) it's
35/// recommended that "provider" libraries maintain their own internal signature
36/// type and use `From` bounds to provide automatic conversions.
37///
38pub trait ToFromBytes: AsRef<[u8]> + Debug + Sized {
39 /// Parse an object from its byte representation
40 fn from_bytes(bytes: &[u8]) -> Result<Self, FastCryptoError>;
41
42 /// Borrow a byte slice representing the serialized form of this object
43 fn as_bytes(&self) -> &[u8] {
44 self.as_ref()
45 }
46}
47
48/// Cryptographic material with an immediate conversion to/from Base64 strings.
49///
50/// This is an [extension trait](https://rust-lang.github.io/rfcs/0445-extension-trait-conventions.html) of `ToFromBytes` above.
51///
52pub trait EncodeDecodeBase64: Sized {
53 fn encode_base64(&self) -> String;
54 fn decode_base64(value: &str) -> FastCryptoResult<Self>;
55}
56
57impl<T: ToFromBytes> EncodeDecodeBase64 for T {
58 fn encode_base64(&self) -> String {
59 Base64::encode(self.as_bytes())
60 }
61
62 fn decode_base64(value: &str) -> FastCryptoResult<Self> {
63 let bytes = Base64::decode(value)?;
64 <T as ToFromBytes>::from_bytes(&bytes)
65 }
66}
67
68/// Trait impl'd by public keys in asymmetric cryptography.
69///
70/// The trait bounds are implemented so as to be symmetric and equivalent
71/// to the ones on its associated types for private and signature material.
72///
73pub trait VerifyingKey:
74 Serialize
75 + DeserializeOwned
76 + std::hash::Hash
77 + Display
78 + Eq // required to make some cached bytes representations explicit.
79 + Ord // required to put keys in BTreeMap.
80 + ToFromBytes
81 + for<'a> From<&'a Self::PrivKey> // conversion PrivateKey -> PublicKey.
82 + Send
83 + Sync
84 + 'static
85 + Clone
86{
87 type PrivKey: SigningKey<PubKey=Self>;
88 type Sig: Authenticator<PubKey=Self>;
89 const LENGTH: usize;
90
91 /// Use Self to verify that the provided signature for a given message bytestring is authentic.
92 /// Returns Error if it is inauthentic, or otherwise returns ().
93 fn verify(&self, msg: &[u8], signature: &Self::Sig) -> Result<(), FastCryptoError>;
94
95 // Expected to be overridden by implementations
96 /// Batch verification over the same message. Implementations of this method can be fast,
97 /// assuming rogue key checks have already been performed.
98 /// TODO: take as input a flag to denote if rogue key protection already took place.
99 ///
100 /// # Example
101 /// ```rust,ignore
102 /// use fastcrypto::ed25519::*;
103 /// # use fastcrypto::{traits::{AggregateAuthenticator, KeyPair, Signer, VerifyingKey}};
104 /// use rand::thread_rng;
105 /// let message: &[u8] = b"Hello, world!";
106 /// let kp1 = Ed25519KeyPair::generate(&mut thread_rng());
107 /// let signature1 = kp1.sign(message);
108 /// let kp2 = Ed25519KeyPair::generate(&mut thread_rng());
109 /// let signature2 = kp2.sign(message);
110 /// let public_keys = [kp1.public().clone(), kp2.public().clone()];
111 /// let signatures = [signature1.clone(), signature2.clone()];
112 /// assert!(Ed25519PublicKey::verify_batch_empty_fail(message, &public_keys, &signatures).is_ok());
113 /// ```
114 #[cfg(any(test))]
115 fn verify_batch_empty_fail(msg: &[u8], pks: &[Self], sigs: &[Self::Sig]) -> FastCryptoResult<()> {
116 if sigs.is_empty() || pks.len() != sigs.len() {
117 return Err(FastCryptoError::InvalidInput);
118 }
119 pks.iter()
120 .zip(sigs)
121 .try_for_each(|(pk, sig)| pk.verify(msg, sig))
122 }
123
124 // Expected to be overridden by implementations
125 /// Batch verification over different messages. Implementations of this method can be fast,
126 /// assuming rogue key checks have already been performed.
127 /// TODO: take as input a flag to denote if rogue key protection already took place.
128 ///
129 /// # Example
130 /// ```rust,ignore
131 /// use fastcrypto::ed25519::*;
132 /// # use fastcrypto::traits::{AggregateAuthenticator, KeyPair, Signer, VerifyingKey};
133 /// use rand::thread_rng;
134 /// let message1: &[u8] = b"Hello, world!";
135 /// let kp1 = Ed25519KeyPair::generate(&mut thread_rng());
136 /// let signature1 = kp1.sign(message1);
137 /// let message2: &[u8] = b"Hello, world!!!";
138 /// let kp2 = Ed25519KeyPair::generate(&mut thread_rng());
139 /// let signature2 = kp2.sign(message2);
140 /// let messages = [message1, message2];
141 /// let public_keys = [kp1.public().clone(), kp2.public().clone()];
142 /// let signatures = [signature1.clone(), signature2.clone()];
143 /// assert!(Ed25519PublicKey::verify_batch_empty_fail_different_msg(&messages, &public_keys, &signatures).is_ok());
144 /// ```
145 #[cfg(any(test))]
146 fn verify_batch_empty_fail_different_msg<'a, M>(msgs: &[M], pks: &[Self], sigs: &[Self::Sig])
147 -> FastCryptoResult<()> where M: Borrow<[u8]> + 'a {
148 if sigs.is_empty() || pks.len() != sigs.len() || pks.len() != msgs.len() {
149 return Err(FastCryptoError::InvalidInput);
150 }
151 pks.iter()
152 .zip(sigs)
153 .zip(msgs)
154 .try_for_each(|((pk, sig), msg)| pk.verify(msg.borrow(), sig))
155 }
156}
157
158/// Trait impl'd by private (secret) keys in asymmetric cryptography.
159///
160/// The trait bounds are implemented so as to be symmetric and equivalent
161/// to the ones on its associated types for public key and signature material.
162///
163pub trait SigningKey: ToFromBytes + Serialize + DeserializeOwned + Send + Sync + 'static {
164 type PubKey: VerifyingKey<PrivKey = Self>;
165 type Sig: Authenticator<PrivKey = Self>;
166 const LENGTH: usize;
167}
168
169/// Trait impl'd by signatures in asymmetric cryptography.
170///
171/// The trait bounds are implemented so as to be symmetric and equivalent
172/// to the ones on its associated types for private key and public key material.
173///
174pub trait Authenticator:
175 ToFromBytes + Display + Serialize + DeserializeOwned + Send + Sync + 'static + Clone
176{
177 type PubKey: VerifyingKey<Sig = Self>;
178 type PrivKey: SigningKey<Sig = Self>;
179 const LENGTH: usize;
180}
181
182/// Trait impl'd by a key/keypair that can create signatures.
183///
184pub trait Signer<Sig> {
185 /// Create a new signature over a message.
186 fn sign(&self, msg: &[u8]) -> Sig;
187}
188
189/// Trait impl'd by a public / private key pair in asymmetric cryptography.
190///
191pub trait KeyPair:
192 Sized + From<Self::PrivKey> + Signer<Self::Sig> + EncodeDecodeBase64 + FromStr
193{
194 type PubKey: VerifyingKey<PrivKey = Self::PrivKey, Sig = Self::Sig>;
195 type PrivKey: SigningKey<PubKey = Self::PubKey, Sig = Self::Sig>;
196 type Sig: Authenticator<PubKey = Self::PubKey, PrivKey = Self::PrivKey>;
197
198 /// Get the public key.
199 fn public(&'_ self) -> &'_ Self::PubKey;
200 /// Get the private key.
201 fn private(self) -> Self::PrivKey;
202
203 // fn copy(&self) -> Self;
204
205 /// Generate a new keypair using the given RNG.
206 fn generate<R: AllowedRng>(rng: &mut R) -> Self;
207}
208
209/// Trait impl'd by public / private keypairs that can generate recoverable signatures
210pub trait RecoverableSigner {
211 type PubKey;
212 type Sig: RecoverableSignature<Signer = Self, PubKey = Self::PubKey>;
213
214 /// Sign as a recoverable signature.
215 fn sign_recoverable(&self, msg: &[u8]) -> Self::Sig {
216 self.sign_recoverable_with_hash::<<<Self as RecoverableSigner>::Sig as RecoverableSignature>::DefaultHash>(msg)
217 }
218
219 /// Sign as a recoverable signature using the given hash function.
220 ///
221 /// Note: This is currently only used for Secp256r1 and Secp256k1 where the hash function must have 32 byte output.
222 fn sign_recoverable_with_hash<H: HashFunction<32>>(&self, msg: &[u8]) -> Self::Sig;
223}
224
225pub trait VerifyRecoverable: Eq + Sized {
226 type Sig: RecoverableSignature<PubKey = Self>;
227
228 /// Verify a recoverable signature by recovering the public key and compare it to self.
229 fn verify_recoverable(&self, msg: &[u8], signature: &Self::Sig) -> Result<(), FastCryptoError> {
230 self.verify_recoverable_with_hash::<<<Self as VerifyRecoverable>::Sig as RecoverableSignature>::DefaultHash>(msg, signature)
231 }
232
233 /// Verify a recoverable signature by recovering the public key and compare it to self.
234 /// The recovery is using the given hash function.
235 ///
236 /// Note: This is currently only used for Secp256r1 and Secp256k1 where the hash function must have 32 byte output.
237 fn verify_recoverable_with_hash<H: HashFunction<32>>(
238 &self,
239 msg: &[u8],
240 signature: &Self::Sig,
241 ) -> Result<(), FastCryptoError> {
242 match signature.recover_with_hash::<H>(msg)? == *self {
243 true => Ok(()),
244 false => Err(FastCryptoError::InvalidSignature),
245 }
246 }
247}
248
249/// Trait impl'd by recoverable signatures
250pub trait RecoverableSignature: Sized {
251 type PubKey;
252 type Signer: RecoverableSigner<Sig = Self, PubKey = Self::PubKey>;
253 type DefaultHash: HashFunction<32>;
254
255 /// Recover the public key from this signature.
256 fn recover(&self, msg: &[u8]) -> Result<Self::PubKey, FastCryptoError> {
257 self.recover_with_hash::<Self::DefaultHash>(msg)
258 }
259
260 /// Recover the public key from this signature. Assuming that the given hash function was used for signing.
261 ///
262 /// Note: This is currently only used for Secp256r1 and Secp256k1 where the hash function must have 32 byte output.
263 fn recover_with_hash<H: HashFunction<32>>(
264 &self,
265 msg: &[u8],
266 ) -> Result<Self::PubKey, FastCryptoError>;
267}
268
269/// Trait impl'd by aggregated signatures in asymmetric cryptography.
270///
271/// The trait bounds are implemented to allow the aggregation of multiple signatures,
272/// and to verify it against multiple, unaggregated public keys. For signature schemes
273/// where aggregation is not possible, a trivial implementation is provided.
274///
275pub trait AggregateAuthenticator:
276 Display + Serialize + DeserializeOwned + Send + Sync + 'static + Clone
277{
278 type Sig: Authenticator<PubKey = Self::PubKey>;
279 type PubKey: VerifyingKey<Sig = Self::Sig>;
280 type PrivKey: SigningKey<Sig = Self::Sig>;
281
282 /// Combine signatures into a single aggregated signature.
283 fn aggregate<'a, K: Borrow<Self::Sig> + 'a, I: IntoIterator<Item = &'a K>>(
284 signatures: I,
285 ) -> Result<Self, FastCryptoError>;
286
287 fn add_signature(&mut self, signature: Self::Sig) -> Result<(), FastCryptoError>;
288 fn add_aggregate(&mut self, signature: Self) -> Result<(), FastCryptoError>;
289
290 /// Verify this aggregate signature assuming that all signatures are over the same message.
291 ///
292 /// # Example
293 /// ```rust,ignore
294 /// use fastcrypto::{traits::{AggregateAuthenticator, KeyPair, Signer, VerifyingKey}};
295 /// use rand::thread_rng;
296 /// use fastcrypto::bls12381::min_sig::{BLS12381AggregateSignature, BLS12381KeyPair};
297 ///
298 /// let message: &[u8] = b"Hello, world!";
299 /// let kp1 = BLS12381KeyPair::generate(&mut thread_rng());
300 /// let signature1 = kp1.sign(message);
301 /// let kp2 = BLS12381KeyPair::generate(&mut thread_rng());
302 /// let signature2 = kp2.sign(message);
303 ///
304 /// let aggregated_signature = BLS12381AggregateSignature::aggregate(vec!(&signature1, &signature2)).unwrap();
305 /// let public_keys = &[kp1.public().clone(), kp2.public().clone()];
306 /// assert!(aggregated_signature.verify(public_keys, message).is_ok());
307 /// ```
308 fn verify(
309 &self,
310 pks: &[<Self::Sig as Authenticator>::PubKey],
311 message: &[u8],
312 ) -> Result<(), FastCryptoError>;
313
314 /// Verify this aggregate signature where the signatures are over different messages.
315 ///
316 /// # Example
317 /// ```rust,ignore
318 /// use fastcrypto::{traits::{AggregateAuthenticator, KeyPair, Signer, VerifyingKey}};
319 /// use rand::thread_rng;
320 /// use fastcrypto::bls12381::min_sig::{BLS12381AggregateSignature, BLS12381KeyPair};
321 ///
322 /// let message1: &[u8] = b"Hello, world!";
323 /// let kp1 = BLS12381KeyPair::generate(&mut thread_rng());
324 /// let signature1 = kp1.sign(message1);
325 /// let message2: &[u8] = b"Hello, world!!!";
326 /// let kp2 = BLS12381KeyPair::generate(&mut thread_rng());
327 /// let signature2 = kp2.sign(message2);
328 ///
329 /// let aggregated_signature = BLS12381AggregateSignature::aggregate(vec!(&signature1, &signature2)).unwrap();
330 /// let messages = [message1, message2];
331 /// let public_keys = [kp1.public().clone(), kp2.public().clone()];
332 /// assert!(aggregated_signature.verify_different_msg(&public_keys, &messages).is_ok());
333 /// ```
334 fn verify_different_msg(
335 &self,
336 pks: &[<Self::Sig as Authenticator>::PubKey],
337 messages: &[&[u8]],
338 ) -> Result<(), FastCryptoError>;
339
340 /// Verify a batch of aggregate signatures, each consisting of a number of signatures over the same message.
341 ///
342 /// # Example
343 /// ```rust,ignore
344 /// use fastcrypto::{traits::{AggregateAuthenticator, KeyPair, Signer, VerifyingKey}};
345 /// use rand::thread_rng;
346 /// use fastcrypto::bls12381::min_sig::{BLS12381AggregateSignature, BLS12381KeyPair};
347 ///
348 /// let message1: &[u8] = b"Hello, world!";
349 /// let kp1 = BLS12381KeyPair::generate(&mut thread_rng());
350 /// let signature1 = kp1.sign(message1);
351 /// let aggregated_signature1 = BLS12381AggregateSignature::aggregate(vec!(&signature1)).unwrap();
352 /// let message2: &[u8] = b"1234";
353 /// let kp2 = BLS12381KeyPair::generate(&mut thread_rng());
354 /// let signature2 = kp2.sign(message2);
355 /// let aggregated_signature2 = BLS12381AggregateSignature::aggregate(vec!(&signature2)).unwrap();
356 ///
357 /// let aggregated_signatures = [&aggregated_signature1, &aggregated_signature2];
358 /// let messages = [message1, message2];
359 /// let pks1 = [kp1.public().clone()];
360 /// let pks2 = [kp2.public().clone()];
361 /// let public_keys = vec!(pks1.iter(), pks2.iter());
362 /// assert!(BLS12381AggregateSignature::batch_verify(&aggregated_signatures, public_keys, &messages).is_ok());
363 /// ```
364 fn batch_verify<'a>(
365 sigs: &[&Self],
366 pks: Vec<impl ExactSizeIterator<Item = &'a Self::PubKey>>,
367 messages: &[&[u8]],
368 ) -> Result<(), FastCryptoError>;
369}
370
371/// Trait impl'd by cryptographic material that can be generated randomly such as keys and nonces.
372///
373pub trait Generate {
374 /// Generate a new random instance using the given RNG.
375 fn generate<R: AllowedRng>(rng: &mut R) -> Self;
376}
377
378/// Trait impl'd by a keys/secret seeds for generating a secure instance.
379///
380pub trait FromUniformBytes<const LENGTH: usize>: ToFromBytes {
381 fn generate<R: AllowedRng>(rng: &mut R) -> Self {
382 let mut bytes = [0u8; LENGTH];
383 rng.fill_bytes(&mut bytes);
384 Self::from_bytes(&bytes).unwrap()
385 }
386}
387
388/// Trait for objects that support an insecure default value that should **only** be used as a
389/// placeholder.
390pub trait InsecureDefault {
391 fn insecure_default() -> Self;
392}
393
394// Whitelist the RNG our APIs accept (see https://rust-random.github.io/book/guide-rngs.html for
395// others).
396/// Trait impl'd by RNG's accepted by vrf-wasm.
397pub trait AllowedRng: CryptoRng + RngCore {}
398
399// Implement AllowedRng for ChaCha20Rng once to avoid conflicts
400impl AllowedRng for rand_chacha::ChaCha20Rng {}