diem_crypto/traits.rs
1// Copyright (c) The Diem Core Contributors
2// SPDX-License-Identifier: Apache-2.0
3
4//! This module provides a generic set of traits for dealing with cryptographic primitives.
5//!
6//! For examples on how to use these traits, see the implementations of the [`ed25519`] or
7//! [`bls12381`] modules.
8
9use crate::hash::CryptoHash;
10use anyhow::Result;
11use core::convert::{From, TryFrom};
12use rand::{rngs::StdRng, CryptoRng, RngCore, SeedableRng};
13use serde::{de::DeserializeOwned, Serialize};
14use std::{fmt::Debug, hash::Hash};
15use thiserror::Error;
16
17/// An error type for key and signature validation issues, see [`ValidCryptoMaterial`][ValidCryptoMaterial].
18///
19/// This enum reflects there are two interesting causes of validation
20/// failure for the ingestion of key or signature material: deserialization errors
21/// (often, due to mangled material or curve equation failure for ECC) and
22/// validation errors (material recognizable but unacceptable for use,
23/// e.g. unsafe).
24#[derive(Clone, Debug, PartialEq, Eq, Error)]
25#[error("{:?}", self)]
26pub enum CryptoMaterialError {
27 /// Struct to be signed does not serialize correctly.
28 SerializationError,
29 /// Key or signature material does not deserialize correctly.
30 DeserializationError,
31 /// Key or signature material deserializes, but is otherwise not valid.
32 ValidationError,
33 /// Key, threshold or signature material does not have the expected size.
34 WrongLengthError,
35 /// Part of the signature or key is not canonical resulting to malleability issues.
36 CanonicalRepresentationError,
37 /// A curve point (i.e., a public key) lies on a small group.
38 SmallSubgroupError,
39 /// A curve point (i.e., a public key) does not satisfy the curve equation.
40 PointNotOnCurveError,
41 /// BitVec errors in accountable multi-sig schemes.
42 BitVecError(String),
43}
44
45/// The serialized length of the data that enables macro derived serialization and deserialization.
46pub trait Length {
47 /// The serialized length of the data
48 fn length(&self) -> usize;
49}
50
51/// Key or more generally crypto material with a notion of byte validation.
52///
53/// A type family for material that knows how to serialize and
54/// deserialize, as well as validate byte-encoded material. The
55/// validation must be implemented as a [`TryFrom`][TryFrom] which
56/// classifies its failures against the above
57/// [`CryptoMaterialError`][CryptoMaterialError].
58///
59/// This provides an implementation for a validation that relies on a
60/// round-trip to bytes and corresponding [`TryFrom`][TryFrom].
61pub trait ValidCryptoMaterial:
62 // The for<'a> exactly matches the assumption "deserializable from any lifetime".
63 for<'a> TryFrom<&'a [u8], Error = CryptoMaterialError> + Serialize + DeserializeOwned
64{
65 /// Convert the valid crypto material to bytes.
66 fn to_bytes(&self) -> Vec<u8>;
67}
68
69/// An extension to to/from Strings for [`ValidCryptoMaterial`][ValidCryptoMaterial].
70///
71/// Relies on [`hex`][::hex] for string encoding / decoding.
72/// No required fields, provides a default implementation.
73pub trait ValidCryptoMaterialStringExt: ValidCryptoMaterial {
74 /// When trying to convert from bytes, we simply decode the string into
75 /// bytes before checking if we can convert.
76 fn from_encoded_string(encoded_str: &str) -> std::result::Result<Self, CryptoMaterialError> {
77 let bytes_out = ::hex::decode(encoded_str);
78 // We defer to `try_from` to make sure we only produce valid crypto materials.
79 bytes_out
80 // We reinterpret a failure to serialize: key is mangled someway.
81 .or(Err(CryptoMaterialError::DeserializationError))
82 .and_then(|ref bytes| Self::try_from(bytes))
83 }
84 /// A function to encode into hex-string after serializing.
85 fn to_encoded_string(&self) -> Result<String> {
86 Ok(::hex::encode(&self.to_bytes()))
87 }
88}
89
90// There's nothing required in this extension, so let's just derive it
91// for anybody that has a ValidCryptoMaterial.
92impl<T: ValidCryptoMaterial> ValidCryptoMaterialStringExt for T {}
93
94/// A type family for key material that should remain secret and has an
95/// associated type of the [`PublicKey`][PublicKey] family.
96pub trait PrivateKey: Sized {
97 /// We require public / private types to be coupled, i.e. their
98 /// associated type is each other.
99 type PublicKeyMaterial: PublicKey<PrivateKeyMaterial = Self>;
100
101 /// Returns the associated public key
102 fn public_key(&self) -> Self::PublicKeyMaterial {
103 self.into()
104 }
105}
106
107/// A type family of valid keys that know how to sign.
108///
109/// This trait has a requirement on a `pub(crate)` marker trait meant to
110/// specifically limit its implementations to the present crate.
111///
112/// A trait for a [`ValidCryptoMaterial`][ValidCryptoMaterial] which knows how to sign a
113/// message, and return an associated `Signature` type.
114pub trait SigningKey:
115 PrivateKey<PublicKeyMaterial = <Self as SigningKey>::VerifyingKeyMaterial>
116 + ValidCryptoMaterial
117 + private::Sealed
118{
119 /// The associated verifying key type for this signing key.
120 type VerifyingKeyMaterial: VerifyingKey<SigningKeyMaterial = Self>;
121 /// The associated signature type for this signing key.
122 type SignatureMaterial: Signature<SigningKeyMaterial = Self>;
123
124 /// Signs an object that has an distinct domain-separation hasher and
125 /// that we know how to serialize. There is no pre-hashing into a
126 /// `HashValue` to be done by the caller.
127 ///
128 /// Note: this assumes serialization is unfaillible. See diem_common::bcs::ser
129 /// for a discussion of this assumption.
130 fn sign<T: CryptoHash + Serialize>(&self, message: &T) -> Self::SignatureMaterial;
131
132 /// Signs a non-hash input message. For testing only.
133 #[cfg(any(test, feature = "fuzzing"))]
134 fn sign_arbitrary_message(&self, message: &[u8]) -> Self::SignatureMaterial;
135
136 /// Returns the associated verifying key
137 fn verifying_key(&self) -> Self::VerifyingKeyMaterial {
138 self.public_key()
139 }
140}
141
142/// A type for key material that can be publicly shared, and in asymmetric
143/// fashion, can be obtained from a [`PrivateKey`][PrivateKey]
144/// reference.
145/// This convertibility requirement ensures the existence of a
146/// deterministic, canonical public key construction from a private key.
147pub trait PublicKey: Sized + Clone + Eq + Hash +
148 // This unsightly turbofish type parameter is the precise constraint
149 // needed to require that there exists an
150 //
151 // ```
152 // impl From<&MyPrivateKeyMaterial> for MyPublicKeyMaterial
153 // ```
154 //
155 // declaration, for any `MyPrivateKeyMaterial`, `MyPublicKeyMaterial`
156 // on which we register (respectively) `PublicKey` and `PrivateKey`
157 // implementations.
158 for<'a> From<&'a <Self as PublicKey>::PrivateKeyMaterial> {
159 /// We require public / private types to be coupled, i.e. their
160 /// associated type is each other.
161 type PrivateKeyMaterial: PrivateKey<PublicKeyMaterial = Self>;
162}
163
164/// A type family of public keys that are used for signing.
165///
166/// This trait has a requirement on a `pub(crate)` marker trait meant to
167/// specifically limit its implementations to the present crate.
168///
169/// It is linked to a type of the Signature family, which carries the
170/// verification implementation.
171pub trait VerifyingKey:
172 PublicKey<PrivateKeyMaterial = <Self as VerifyingKey>::SigningKeyMaterial>
173 + ValidCryptoMaterial
174 + private::Sealed
175{
176 /// The associated signing key type for this verifying key.
177 type SigningKeyMaterial: SigningKey<VerifyingKeyMaterial = Self>;
178 /// The associated signature type for this verifying key.
179 type SignatureMaterial: Signature<VerifyingKeyMaterial = Self>;
180
181 /// We provide the striaghtfoward implementation which dispatches to the signature.
182 fn verify_struct_signature<T: CryptoHash + Serialize>(
183 &self,
184 message: &T,
185 signature: &Self::SignatureMaterial,
186 ) -> Result<()> {
187 signature.verify(message, self)
188 }
189
190 /// We provide the implementation which dispatches to the signature.
191 fn batch_verify<T: CryptoHash + Serialize>(
192 message: &T,
193 keys_and_signatures: Vec<(Self, Self::SignatureMaterial)>,
194 ) -> Result<()> {
195 Self::SignatureMaterial::batch_verify(message, keys_and_signatures)
196 }
197}
198
199/// A type family for signature material that knows which public key type
200/// is needed to verify it, and given such a public key, knows how to
201/// verify.
202///
203/// This trait simply requires an association to some type of the
204/// [`PublicKey`][PublicKey] family of which we are the `SignatureMaterial`.
205///
206/// This trait has a requirement on a `pub(crate)` marker trait meant to
207/// specifically limit its implementations to the present crate.
208///
209/// It should be possible to write a generic signature function that
210/// checks signature material passed as `&[u8]` and only returns Ok when
211/// that material de-serializes to a signature of the expected concrete
212/// scheme. This would be done as an extension trait of
213/// [`Signature`][Signature].
214pub trait Signature:
215 for<'a> TryFrom<&'a [u8], Error = CryptoMaterialError>
216 + Sized
217 + Debug
218 + Clone
219 + Eq
220 + Hash
221 + private::Sealed
222{
223 /// The associated verifying key type for this signature.
224 type VerifyingKeyMaterial: VerifyingKey<SignatureMaterial = Self>;
225 /// The associated signing key type for this signature
226 type SigningKeyMaterial: SigningKey<SignatureMaterial = Self>;
227
228 /// Verification for a struct we unabmiguously know how to serialize and
229 /// that we have a domain separation prefix for.
230 fn verify<T: CryptoHash + Serialize>(
231 &self,
232 message: &T,
233 public_key: &Self::VerifyingKeyMaterial,
234 ) -> Result<()>;
235
236 /// Native verification function.
237 fn verify_arbitrary_msg(
238 &self,
239 message: &[u8],
240 public_key: &Self::VerifyingKeyMaterial,
241 ) -> Result<()>;
242
243 /// Convert the signature into a byte representation.
244 fn to_bytes(&self) -> Vec<u8>;
245
246 /// The implementer can override a batch verification implementation
247 /// that by default iterates over each signature. More efficient
248 /// implementations exist and should be implemented for many schemes.
249 fn batch_verify<T: CryptoHash + Serialize>(
250 message: &T,
251 keys_and_signatures: Vec<(Self::VerifyingKeyMaterial, Self)>,
252 ) -> Result<()> {
253 for (key, signature) in keys_and_signatures {
254 signature.verify(message, &key)?
255 }
256 Ok(())
257 }
258}
259
260/// A type family for schemes which know how to generate key material from
261/// a cryptographically-secure [`CryptoRng`][::rand::CryptoRng].
262pub trait Uniform {
263 /// Generate key material from an RNG. This should generally not be used for production
264 /// purposes even with a good source of randomness. When possible use hardware crypto to generate and
265 /// store private keys.
266 fn generate<R>(rng: &mut R) -> Self
267 where
268 R: RngCore + CryptoRng;
269
270 /// Generate a random key using the shared TEST_SEED
271 fn generate_for_testing() -> Self
272 where
273 Self: Sized,
274 {
275 let mut rng: StdRng = SeedableRng::from_seed(crate::test_utils::TEST_SEED);
276 Self::generate(&mut rng)
277 }
278}
279
280/// A type family with a by-convention notion of genesis private key.
281pub trait Genesis: PrivateKey {
282 /// Produces the genesis private key.
283 fn genesis() -> Self;
284}
285
286/// A pub(crate) mod hiding a Sealed trait and its implementations, allowing
287/// us to make sure implementations are constrained to the crypto crate.
288// See https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed
289pub(crate) mod private {
290 pub trait Sealed {}
291
292 // Implement for the ed25519, multi-ed25519 signatures
293 impl Sealed for crate::ed25519::Ed25519PrivateKey {}
294 impl Sealed for crate::ed25519::Ed25519PublicKey {}
295 impl Sealed for crate::ed25519::Ed25519Signature {}
296
297 impl Sealed for crate::multi_ed25519::MultiEd25519PrivateKey {}
298 impl Sealed for crate::multi_ed25519::MultiEd25519PublicKey {}
299 impl Sealed for crate::multi_ed25519::MultiEd25519Signature {}
300}