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