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}