wamu_core/
crypto.rs

1//! Types, abstractions and utilities for lower-level cryptography.
2
3use crypto_bigint::modular::constant_mod::ResidueParams;
4use crypto_bigint::{impl_modulus, Encoding, NonZero, Random, RandomMod, U256};
5use std::fmt;
6use zeroize::Zeroize;
7
8use crate::errors::{CryptoError, Error};
9
10// Order of the `Secp256k1` elliptic curve a `crypto-bigint` modulus type.
11// Ref: <https://www.secg.org/sec2-v2.pdf>.
12// Ref: <https://en.bitcoin.it/wiki/Secp256k1>.
13impl_modulus!(
14    Secp256k1Order,
15    U256,
16    "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"
17);
18
19/// A convenience wrapper for generating and encoding/decoding cryptographically secure random values.
20// No `ZeroizeOnDrop` because we want `Random32Bytes` to be `Copy` like `U256`.
21#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Zeroize)]
22pub struct Random32Bytes(U256);
23
24impl Random32Bytes {
25    /// Generates a cryptographically secure random value.
26    pub fn generate() -> Self {
27        let mut rng = rand::thread_rng();
28        Self(U256::random(&mut rng))
29    }
30
31    /// Generates a cryptographically secure random value which is less than the order of the `Secp256k1` elliptic curve.
32    pub fn generate_mod_q() -> Self {
33        let mut rng = rand::thread_rng();
34
35        // The order of the `Secp256k1` curve should be non-zero.
36        let modulus = NonZero::new(Secp256k1Order::MODULUS).unwrap();
37        Self(U256::random_mod(&mut rng, &modulus))
38    }
39
40    /// Returns the underlying `U256` random value.
41    pub fn as_u256(&self) -> U256 {
42        self.0
43    }
44
45    /// Returns 32 bytes representation of the "secret share".
46    pub fn to_be_bytes(&self) -> [u8; 32] {
47        self.0.to_be_bytes()
48    }
49}
50
51impl From<U256> for Random32Bytes {
52    /// Converts a U256 into a `RandomBytes` representation.
53    fn from(value: U256) -> Self {
54        Self(value)
55    }
56}
57
58impl From<[u8; 32]> for Random32Bytes {
59    /// Converts a 32 byte slice into a `RandomBytes` representation.
60    fn from(value: [u8; 32]) -> Self {
61        Self(U256::from_be_slice(&value))
62    }
63}
64
65impl TryFrom<&[u8]> for Random32Bytes {
66    type Error = Error;
67
68    /// Converts a slice of bytes into a `RandomBytes` representation.
69    fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
70        // Input slice must be 32 bytes long.
71        if slice.len() == 32 {
72            Ok(Self(U256::from_be_slice(slice)))
73        } else {
74            Err(Error::Encoding)
75        }
76    }
77}
78
79impl fmt::Display for Random32Bytes {
80    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81        write!(f, "{}", self.as_u256())
82    }
83}
84
85/// Returns an `Ok` result for valid signature for the message, or an appropriate `Err` result otherwise.
86pub fn verify_signature(
87    verifying_key: &VerifyingKey,
88    msg: &[u8],
89    signature: &Signature,
90) -> Result<(), CryptoError> {
91    if (verifying_key.algo, verifying_key.curve) != (signature.algo, signature.curve) {
92        // Signature algorithm and elliptic curve for the verifying key and signature should match.
93        Err(CryptoError::SchemeMismatch)
94    } else {
95        // Matches signature scheme (algorithm + curve).
96        match (verifying_key.algo, verifying_key.curve) {
97            // Verifies ECDSA/Secp256k1 signatures.
98            // SEC1 encoded verifying key and SHA-256 digest and DER encoded signature.
99            (SignatureAlgorithm::ECDSA, EllipticCurve::Secp256k1) => {
100                // Matches the message digest/hash function.
101                match signature.hash {
102                    // Verifies ECDSA/Secp256k1/SHA-256 signatures.
103                    MessageDigest::SHA256 => {
104                        // Matches verifying key and signature encoding.
105                        match (verifying_key.enc, signature.enc) {
106                            // Verifies DER encoded ECDSA/Secp256k1/SHA-256 signatures with SEC1 encoded verifying key.
107                            (KeyEncoding::SEC1, SignatureEncoding::DER) => {
108                                // Deserialize verifying key.
109                                // `k256::ecdsa::VerifyingKey` uses `Secp256k1` and `SHA-256`.
110                                let ver_key =
111                                    k256::ecdsa::VerifyingKey::from_sec1_bytes(&verifying_key.key);
112                                // Deserialize signature.
113                                let sig = k256::ecdsa::Signature::from_der(&signature.sig)
114                                    .map_err(|_| CryptoError::InvalidSignature)?;
115                                // Verify ECDSA/Secp256k1/SHA-256 signature.
116                                use k256::ecdsa::signature::Verifier;
117                                ver_key
118                                    .map_err(|_| CryptoError::InvalidVerifyingKey)?
119                                    .verify(msg, &sig)
120                                    .map_err(|_| CryptoError::InvalidSignature)
121                            }
122                            _ => Err(CryptoError::UnsupportedEncoding),
123                        }
124                    }
125                    _ => Err(CryptoError::UnsupportedDigest),
126                }
127            }
128            _ => Err(CryptoError::UnsupportedScheme),
129        }
130    }
131}
132
133/// A verifying key (e.g an ECDSA/secp256k1 public key).
134#[derive(Debug, Clone, PartialEq, Eq)]
135pub struct VerifyingKey {
136    /// The verifying key as a sequence of bytes.
137    pub key: Vec<u8>,
138    /// The signature algorithm.
139    pub algo: SignatureAlgorithm,
140    /// The elliptic curve.
141    pub curve: EllipticCurve,
142    /// The encoding standard used for the verifying key.
143    pub enc: KeyEncoding,
144}
145
146/// A signature (e.g a ECDSA/secp256k1/SHA-256 signature).
147#[derive(Debug, Clone, PartialEq, Eq)]
148pub struct Signature {
149    /// The signature as a sequence of bytes.
150    pub sig: Vec<u8>,
151    /// The signature algorithm.
152    pub algo: SignatureAlgorithm,
153    /// The elliptic curve.
154    pub curve: EllipticCurve,
155    /// The hash function.
156    pub hash: MessageDigest,
157    /// The encoding standard used for the signature.
158    pub enc: SignatureEncoding,
159}
160
161/// A signature algorithm.
162#[derive(Debug, Clone, Copy, PartialEq, Eq)]
163#[non_exhaustive]
164pub enum SignatureAlgorithm {
165    /// Ref: <https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm>.
166    ECDSA,
167    /// Ref: <https://en.wikipedia.org/wiki/EdDSA>.
168    EdDSA,
169}
170
171/// An elliptic curve.
172#[derive(Debug, Clone, Copy, PartialEq, Eq)]
173pub enum EllipticCurve {
174    /// Ref: <https://www.secg.org/sec2-v2.pdf>.
175    Secp256k1,
176    /// Ref: <https://en.wikipedia.org/wiki/Curve25519>.
177    Curve25519,
178}
179
180/// A cryptographic message digest/hash function.
181#[derive(Debug, Clone, Copy, PartialEq, Eq)]
182pub enum MessageDigest {
183    /// Ref: <https://en.wikipedia.org/wiki/SHA-2>.
184    SHA256,
185    /// Ref: <https://en.wikipedia.org/wiki/SHA-3>.
186    Keccak256,
187}
188
189/// A key encoding format.
190#[derive(Debug, Clone, Copy, PartialEq, Eq)]
191pub enum KeyEncoding {
192    /// Ref: <https://www.secg.org/sec1-v2.pdf>.
193    SEC1,
194    /// Ref: <https://eips.ethereum.org/EIPS/eip-55>.
195    EIP55,
196}
197
198/// A signature encoding format.
199#[derive(Debug, Clone, Copy, PartialEq, Eq)]
200pub enum SignatureEncoding {
201    /// Ref: <https://en.wikipedia.org/wiki/X.690#DER_encoding>.
202    DER,
203    /// Ref: <https://ethereum.org/en/developers/docs/data-structures-and-encoding/rlp/>.
204    RLP,
205}