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}