dcrypt_sign/eddsa/ed25519/
mod.rs1#[cfg(not(feature = "std"))]
11use alloc::vec::Vec;
12
13use super::constants::{ED25519_PUBLIC_KEY_SIZE, ED25519_SECRET_KEY_SIZE, ED25519_SIGNATURE_SIZE};
14use curve25519_dalek::edwards::CompressedEdwardsY;
15use dcrypt_api::{error::Error as ApiError, Result as ApiResult, Signature as SignatureTrait};
16use ed25519_dalek::{Signature as DalekSignature, Signer, SigningKey, VerifyingKey};
17use rand::{CryptoRng, RngCore};
18use zeroize::{Zeroize, Zeroizing};
19
20pub struct Ed25519;
22
23#[derive(Clone, Zeroize)]
25pub struct Ed25519PublicKey(pub [u8; ED25519_PUBLIC_KEY_SIZE]);
26
27impl core::fmt::Debug for Ed25519PublicKey {
28 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
29 f.debug_struct("Ed25519PublicKey")
30 .field("algorithm", &"Ed25519")
31 .finish()
32 }
33}
34
35#[derive(Clone)]
37pub struct Ed25519SecretKey {
38 seed: [u8; ED25519_SECRET_KEY_SIZE],
39}
40
41impl Zeroize for Ed25519SecretKey {
42 fn zeroize(&mut self) {
43 self.seed.zeroize();
44 }
45}
46
47impl Drop for Ed25519SecretKey {
48 fn drop(&mut self) {
49 self.zeroize();
50 }
51}
52
53impl core::fmt::Debug for Ed25519SecretKey {
54 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
55 f.debug_struct("Ed25519SecretKey")
56 .field("algorithm", &"Ed25519")
57 .finish()
58 }
59}
60
61#[derive(Clone, Zeroize)]
63pub struct Ed25519Signature(pub [u8; ED25519_SIGNATURE_SIZE]);
64
65impl core::fmt::Debug for Ed25519Signature {
66 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
67 f.debug_struct("Ed25519Signature")
68 .field("length", &self.0.len())
69 .finish()
70 }
71}
72
73fn invalid_key(context: &'static str, message: &'static str) -> ApiError {
74 ApiError::InvalidKey {
75 context,
76 #[cfg(feature = "std")]
77 message: message.to_string(),
78 }
79}
80
81fn invalid_signature(context: &'static str, message: &'static str) -> ApiError {
82 ApiError::InvalidSignature {
83 context,
84 #[cfg(feature = "std")]
85 message: message.to_string(),
86 }
87}
88
89fn validate_canonical_prime_order_point(bytes: &[u8; 32], context: &'static str) -> ApiResult<()> {
90 let point = CompressedEdwardsY(*bytes)
91 .decompress()
92 .ok_or_else(|| invalid_key(context, "point encoding does not decompress"))?;
93 if point.compress().to_bytes() != *bytes {
94 return Err(invalid_key(context, "point encoding is non-canonical"));
95 }
96 if point.is_small_order() || !point.is_torsion_free() {
97 return Err(invalid_key(
98 context,
99 "point is not in the prime-order subgroup",
100 ));
101 }
102 Ok(())
103}
104
105impl Ed25519PublicKey {
106 pub fn from_bytes(bytes: &[u8]) -> ApiResult<Self> {
108 let key_bytes: [u8; ED25519_PUBLIC_KEY_SIZE] =
109 bytes.try_into().map_err(|_| ApiError::InvalidLength {
110 context: "Ed25519PublicKey::from_bytes",
111 expected: ED25519_PUBLIC_KEY_SIZE,
112 actual: bytes.len(),
113 })?;
114 validate_canonical_prime_order_point(&key_bytes, "Ed25519PublicKey::from_bytes")?;
115 VerifyingKey::from_bytes(&key_bytes).map_err(|_| {
116 invalid_key(
117 "Ed25519PublicKey::from_bytes",
118 "public key is not a canonical Edwards point",
119 )
120 })?;
121 Ok(Self(key_bytes))
122 }
123
124 pub fn to_bytes(&self) -> [u8; ED25519_PUBLIC_KEY_SIZE] {
125 self.0
126 }
127
128 fn verifying_key(&self) -> ApiResult<VerifyingKey> {
129 validate_canonical_prime_order_point(&self.0, "Ed25519 verify")?;
130 let key = VerifyingKey::from_bytes(&self.0)
131 .map_err(|_| invalid_key("Ed25519 verify", "public key encoding is invalid"))?;
132 Ok(key)
133 }
134}
135
136impl Ed25519SecretKey {
137 pub fn from_seed(seed: &[u8; ED25519_SECRET_KEY_SIZE]) -> ApiResult<Self> {
138 Ok(Self { seed: *seed })
139 }
140
141 pub fn seed(&self) -> &[u8; ED25519_SECRET_KEY_SIZE] {
142 &self.seed
143 }
144
145 pub fn export_seed(&self) -> Zeroizing<Vec<u8>> {
146 Zeroizing::new(self.seed.to_vec())
147 }
148
149 pub fn public_key(&self) -> ApiResult<Ed25519PublicKey> {
150 Ed25519::derive_public_from_secret(self)
151 }
152
153 fn signing_key(&self) -> SigningKey {
154 SigningKey::from_bytes(&self.seed)
155 }
156}
157
158impl Ed25519Signature {
159 pub fn from_bytes(bytes: &[u8]) -> ApiResult<Self> {
160 let signature: [u8; ED25519_SIGNATURE_SIZE] =
161 bytes.try_into().map_err(|_| ApiError::InvalidLength {
162 context: "Ed25519Signature::from_bytes",
163 expected: ED25519_SIGNATURE_SIZE,
164 actual: bytes.len(),
165 })?;
166 Ok(Self(signature))
167 }
168
169 pub fn to_bytes(&self) -> [u8; ED25519_SIGNATURE_SIZE] {
170 self.0
171 }
172}
173
174impl SignatureTrait for Ed25519 {
175 type PublicKey = Ed25519PublicKey;
176 type SecretKey = Ed25519SecretKey;
177 type SignatureData = Ed25519Signature;
178 type KeyPair = (Self::PublicKey, Self::SecretKey);
179
180 fn name() -> &'static str {
181 "Ed25519"
182 }
183
184 fn keypair<R: CryptoRng + RngCore>(rng: &mut R) -> ApiResult<Self::KeyPair> {
185 let mut seed = [0u8; ED25519_SECRET_KEY_SIZE];
186 rng.fill_bytes(&mut seed);
187 let secret = Ed25519SecretKey::from_seed(&seed)?;
188 seed.zeroize();
189 let public = secret.public_key()?;
190 Ok((public, secret))
191 }
192
193 fn public_key(keypair: &Self::KeyPair) -> Self::PublicKey {
194 keypair.0.clone()
195 }
196
197 fn secret_key(keypair: &Self::KeyPair) -> Self::SecretKey {
198 keypair.1.clone()
199 }
200
201 fn sign(message: &[u8], secret_key: &Self::SecretKey) -> ApiResult<Self::SignatureData> {
202 let signature: DalekSignature = secret_key.signing_key().sign(message);
203 Ok(Ed25519Signature(signature.to_bytes()))
204 }
205
206 fn verify(
207 message: &[u8],
208 signature: &Self::SignatureData,
209 public_key: &Self::PublicKey,
210 ) -> ApiResult<()> {
211 let verifying_key = public_key.verifying_key()?;
212 let r_bytes: [u8; 32] = signature.0[..32]
213 .try_into()
214 .map_err(|_| invalid_signature("Ed25519 verify", "invalid R encoding"))?;
215 validate_canonical_prime_order_point(&r_bytes, "Ed25519 signature R")
216 .map_err(|_| invalid_signature("Ed25519 verify", "R is non-canonical or torsion"))?;
217 let signature = DalekSignature::from_bytes(&signature.0);
218 verifying_key
219 .verify_strict(message, &signature)
220 .map_err(|_| invalid_signature("Ed25519 verify", "strict verification failed"))
221 }
222}
223
224impl Ed25519 {
225 pub fn derive_public_from_secret(secret_key: &Ed25519SecretKey) -> ApiResult<Ed25519PublicKey> {
226 let bytes = secret_key.signing_key().verifying_key().to_bytes();
227 Ed25519PublicKey::from_bytes(&bytes)
228 }
229}
230
231#[cfg(test)]
232mod tests;