ed25519_zebra/
signing_key.rs1#[cfg(feature = "pkcs8")]
2const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.101.112"); #[cfg(feature = "pkcs8")]
4const ALGORITHM_ID: AlgorithmIdentifierRef = AlgorithmIdentifierRef {
5 oid: OID,
6 parameters: None,
7};
8
9use crate::Error;
10#[cfg(all(feature = "pem", feature = "pkcs8"))]
11use alloc::string::String;
12use core::convert::TryFrom;
13#[cfg(feature = "pkcs8")]
14use core::convert::TryInto;
15use curve25519_dalek::{constants, digest::Update, scalar::Scalar};
16use rand_core::{CryptoRng, RngCore};
17use sha2::{Digest, Sha512};
18use subtle::ConstantTimeEq;
19use zeroize::Zeroize;
20
21use ed25519::{signature::Signer, Signature};
22
23#[cfg(feature = "pkcs8")]
24use ed25519::KeypairBytes;
25#[cfg(feature = "pem")]
26use ed25519::PublicKeyBytes;
27
28#[cfg(all(feature = "pem", feature = "pkcs8"))]
29use der::pem::LineEnding;
30#[cfg(feature = "pkcs8")]
31use pkcs8::der::SecretDocument;
32#[cfg(feature = "pkcs8")]
33use pkcs8::{
34 spki::AlgorithmIdentifierRef, DecodePrivateKey, DecodePublicKey, Document, EncodePrivateKey,
35 EncodePublicKey, ObjectIdentifier, PrivateKeyInfo,
36};
37#[cfg(all(feature = "pem", feature = "pkcs8"))]
38use zeroize::Zeroizing;
39
40#[cfg(all(feature = "pem", feature = "pkcs8"))]
41use pkcs8::der::pem::PemLabel;
42
43use crate::{VerificationKey, VerificationKeyBytes};
44
45pub const SECRET_KEY_LENGTH: usize = 32;
47
48pub type SecretKey = [u8; SECRET_KEY_LENGTH];
55
56#[derive(Copy, Clone, Zeroize)]
60#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
61#[cfg_attr(feature = "serde", serde(from = "SerdeHelper"))]
62#[cfg_attr(feature = "serde", serde(into = "SerdeHelper"))]
63pub struct SigningKey {
64 seed: SecretKey,
65 s: Scalar,
66 prefix: [u8; 32],
67 vk: VerificationKey,
68}
69
70impl core::fmt::Debug for SigningKey {
71 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
72 fmt.debug_struct("SigningKey")
73 .field("vk", &self.vk)
74 .finish()
75 }
76}
77
78impl<'a> From<&'a SigningKey> for VerificationKey {
79 fn from(sk: &'a SigningKey) -> VerificationKey {
80 sk.vk
81 }
82}
83
84impl<'a> From<&'a SigningKey> for VerificationKeyBytes {
85 fn from(sk: &'a SigningKey) -> VerificationKeyBytes {
86 sk.vk.into()
87 }
88}
89
90impl AsRef<[u8]> for SigningKey {
91 fn as_ref(&self) -> &[u8] {
92 &self.seed[..]
93 }
94}
95
96impl From<SigningKey> for SecretKey {
97 fn from(sk: SigningKey) -> SecretKey {
98 sk.seed
99 }
100}
101
102impl TryFrom<&[u8]> for SigningKey {
103 type Error = Error;
104 fn try_from(slice: &[u8]) -> Result<SigningKey, Self::Error> {
105 if slice.len() == 32 {
106 let mut bytes = [0u8; 32];
107 bytes[..].copy_from_slice(slice);
108 Ok(bytes.into())
109 } else {
110 Err(Self::Error::InvalidSliceLength)
111 }
112 }
113}
114
115impl From<SecretKey> for SigningKey {
116 #[allow(non_snake_case)]
117 fn from(seed: [u8; 32]) -> SigningKey {
118 let h = Sha512::digest(&seed[..]);
120
121 let s = {
123 let mut scalar_bytes = [0u8; 32];
124 scalar_bytes[..].copy_from_slice(&h[0..32]);
125 scalar_bytes[0] &= 248;
126 scalar_bytes[31] &= 127;
127 scalar_bytes[31] |= 64;
128 Scalar::from_bytes_mod_order(scalar_bytes)
129 };
130
131 let prefix = {
133 let mut prefix = [0u8; 32];
134 prefix[..].copy_from_slice(&h[32..64]);
135 prefix
136 };
137
138 let A = &s * constants::ED25519_BASEPOINT_TABLE;
140
141 SigningKey {
142 seed,
143 s,
144 prefix,
145 vk: VerificationKey {
146 minus_A: -A,
147 A_bytes: VerificationKeyBytes(A.compress().to_bytes()),
148 },
149 }
150 }
151}
152
153impl ConstantTimeEq for SigningKey {
154 fn ct_eq(&self, other: &Self) -> subtle::Choice {
155 self.seed.ct_eq(&other.seed)
156 }
157}
158
159impl PartialEq for SigningKey {
160 fn eq(&self, other: &Self) -> bool {
161 self.ct_eq(other).into()
162 }
163}
164
165impl Eq for SigningKey {}
166
167#[cfg(feature = "pkcs8")]
168impl<'a> TryFrom<PrivateKeyInfo<'a>> for SigningKey {
169 type Error = Error;
170 fn try_from(pki: PrivateKeyInfo) -> Result<Self, Self::Error> {
171 if pki.algorithm == ALGORITHM_ID {
172 SigningKey::try_from(pki.private_key)
173 } else {
174 Err(Self::Error::MalformedSecretKey)
175 }
176 }
177}
178
179#[cfg(feature = "pkcs8")]
180impl EncodePublicKey for SigningKey {
181 fn to_public_key_der(&self) -> pkcs8::spki::Result<Document> {
183 self.vk.to_public_key_der()
184 }
185}
186
187impl Signer<Signature> for SigningKey {
188 fn try_sign(&self, message: &[u8]) -> Result<Signature, ed25519::signature::Error> {
190 Ok(self.sign(message))
191 }
192}
193
194#[cfg(feature = "pkcs8")]
195impl TryFrom<KeypairBytes> for SigningKey {
196 type Error = pkcs8::Error;
197
198 fn try_from(pkcs8_key: KeypairBytes) -> pkcs8::Result<Self> {
199 SigningKey::try_from(&pkcs8_key)
200 }
201}
202
203#[cfg(feature = "pkcs8")]
204impl TryFrom<&KeypairBytes> for SigningKey {
205 type Error = pkcs8::Error;
206
207 fn try_from(pkcs8_key: &KeypairBytes) -> pkcs8::Result<Self> {
208 let signing_key = SigningKey::from_der(&pkcs8_key.secret_key);
209
210 if let Some(public_bytes) = &pkcs8_key.public_key {
212 let expected_verifying_key =
213 VerificationKey::from_public_key_der(public_bytes.as_ref())
214 .map_err(|_| pkcs8::Error::KeyMalformed)?;
215
216 if VerificationKey::from(&signing_key.unwrap()).A_bytes != expected_verifying_key.into()
217 {
218 return Err(pkcs8::Error::KeyMalformed);
219 }
220 }
221
222 signing_key
223 }
224}
225
226#[cfg(feature = "pem")]
227impl From<SigningKey> for KeypairBytes {
228 fn from(signing_key: SigningKey) -> KeypairBytes {
229 KeypairBytes::from(&signing_key)
230 }
231}
232
233#[cfg(feature = "pem")]
234impl From<&SigningKey> for KeypairBytes {
235 fn from(signing_key: &SigningKey) -> KeypairBytes {
236 KeypairBytes {
237 secret_key: signing_key.s.to_bytes(),
238 public_key: Some(PublicKeyBytes(signing_key.vk.into())),
239 }
240 }
241}
242
243#[cfg(feature = "pkcs8")]
244impl EncodePrivateKey for SigningKey {
245 fn to_pkcs8_der(&self) -> pkcs8::Result<SecretDocument> {
248 let mut final_key = [0u8; 34];
252 final_key[..2].copy_from_slice(&[0x04, 0x20]);
253 final_key[2..].copy_from_slice(&self.seed);
254 SecretDocument::try_from(PrivateKeyInfo {
255 algorithm: ALGORITHM_ID,
256 private_key: &final_key,
257 public_key: Some(self.vk.A_bytes.0.as_slice()),
258 })
259 }
260}
261
262#[cfg(feature = "pkcs8")]
263impl DecodePrivateKey for SigningKey {
264 fn from_pkcs8_der(bytes: &[u8]) -> pkcs8::Result<Self> {
269 let keypair = KeypairBytes::from_pkcs8_der(bytes).unwrap();
270 let sk = SigningKey::from(keypair.secret_key);
271 match keypair.public_key {
272 Some(vk2) => {
273 if sk.vk.A_bytes.0 == vk2.to_bytes() {
274 Ok(sk)
275 } else {
276 Err(pkcs8::Error::KeyMalformed)
277 }
278 }
279 None => Ok(sk),
280 }
281 }
282}
283
284#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
285struct SerdeHelper([u8; 32]);
286
287impl From<SerdeHelper> for SigningKey {
288 fn from(helper: SerdeHelper) -> SigningKey {
289 helper.0.into()
290 }
291}
292
293impl From<SigningKey> for SerdeHelper {
294 fn from(sk: SigningKey) -> Self {
295 Self(sk.into())
296 }
297}
298
299impl SigningKey {
300 #[inline]
303 pub fn from_bytes(secret_key: &SecretKey) -> Self {
304 (*secret_key).into()
305 }
306
307 #[inline]
309 pub fn to_bytes(&self) -> SecretKey {
310 (*self).into()
311 }
312
313 #[inline]
315 pub fn as_bytes(&self) -> &SecretKey {
316 &self.seed
317 }
318
319 pub fn new<R: RngCore + CryptoRng>(mut rng: R) -> SigningKey {
321 let mut bytes = [0u8; 32];
322 rng.fill_bytes(&mut bytes[..]);
323 bytes.into()
324 }
325
326 pub fn verification_key(&self) -> VerificationKey {
328 self.into()
329 }
330
331 #[allow(non_snake_case)]
333 pub fn sign(&self, msg: &[u8]) -> Signature {
334 let r = Scalar::from_hash(Sha512::default().chain(&self.prefix[..]).chain(msg));
335
336 let R_bytes = (&r * constants::ED25519_BASEPOINT_TABLE)
337 .compress()
338 .to_bytes();
339
340 let k = Scalar::from_hash(
341 Sha512::default()
342 .chain(&R_bytes[..])
343 .chain(&self.vk.A_bytes.0[..])
344 .chain(msg),
345 );
346
347 let s_bytes = (r + k * self.s).to_bytes();
348
349 Signature::from_components(R_bytes, s_bytes)
350 }
351
352 #[cfg(feature = "pkcs8")]
354 pub fn from_der(bytes: &[u8]) -> pkcs8::Result<Self> {
355 bytes
356 .try_into()
357 .map_err(|_| pkcs8::Error::ParametersMalformed)
358 }
359
360 #[cfg(feature = "pkcs8")]
363 pub fn to_pkcs8_der_v1(&self) -> pkcs8::Result<SecretDocument> {
364 let mut final_key = [0u8; 34];
368 final_key[..2].copy_from_slice(&[0x04, 0x20]);
369 final_key[2..].copy_from_slice(&self.seed);
370 SecretDocument::try_from(PrivateKeyInfo::new(ALGORITHM_ID, &final_key))
371 }
372
373 #[cfg(all(feature = "pem", feature = "pkcs8"))]
376 pub fn to_pkcs8_pem_v1(
377 &self,
378 line_ending: LineEnding,
379 ) -> Result<Zeroizing<String>, pkcs8::Error> {
380 let doc = self.to_pkcs8_der_v1()?;
381 Ok(doc.to_pem(PrivateKeyInfo::PEM_LABEL, line_ending)?)
382 }
383}