ed25519_zebra/
signing_key.rs

1#[cfg(feature = "pkcs8")]
2const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.101.112"); // RFC 8410
3#[cfg(feature = "pkcs8")]
4const ALGORITHM_ID: AlgorithmIdentifierRef = AlgorithmIdentifierRef {
5    oid: OID,
6    parameters: None,
7};
8
9use crate::Error;
10use core::convert::TryFrom;
11#[cfg(feature = "pem")]
12use core::convert::TryInto;
13use curve25519_dalek::{constants, digest::Update, scalar::Scalar};
14use rand_core::{CryptoRng, RngCore};
15use sha2::{Digest, Sha512};
16use zeroize::Zeroize;
17
18pub use ed25519::{
19    signature::{Signer, Verifier},
20    ComponentBytes, Error as Ed25519Error, Signature,
21};
22
23#[cfg(feature = "pem")]
24pub use ed25519::{KeypairBytes, PublicKeyBytes};
25
26#[cfg(all(feature = "pem", feature = "pkcs8"))]
27use der::pem::LineEnding;
28#[cfg(feature = "pkcs8")]
29use pkcs8::der::SecretDocument;
30#[cfg(feature = "pkcs8")]
31use pkcs8::{
32    spki::AlgorithmIdentifierRef, DecodePrivateKey, DecodePublicKey, Document, EncodePrivateKey,
33    EncodePublicKey, ObjectIdentifier, PrivateKeyInfo,
34};
35#[cfg(all(feature = "pem", feature = "pkcs8"))]
36use zeroize::Zeroizing;
37
38#[cfg(all(feature = "pem", feature = "pkcs8"))]
39use pkcs8::der::pem::PemLabel;
40
41use crate::{VerificationKey, VerificationKeyBytes};
42
43/// An Ed25519 signing key.
44///
45/// This is also called a secret key by other implementations.
46#[derive(Copy, Clone, Zeroize)]
47#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
48#[cfg_attr(feature = "serde", serde(from = "SerdeHelper"))]
49#[cfg_attr(feature = "serde", serde(into = "SerdeHelper"))]
50pub struct SigningKey {
51    seed: [u8; 32],
52    s: Scalar,
53    prefix: [u8; 32],
54    vk: VerificationKey,
55}
56
57impl core::fmt::Debug for SigningKey {
58    fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
59        fmt.debug_struct("SigningKey")
60            .field("vk", &self.vk)
61            .finish()
62    }
63}
64
65impl<'a> From<&'a SigningKey> for VerificationKey {
66    fn from(sk: &'a SigningKey) -> VerificationKey {
67        sk.vk
68    }
69}
70
71impl<'a> From<&'a SigningKey> for VerificationKeyBytes {
72    fn from(sk: &'a SigningKey) -> VerificationKeyBytes {
73        sk.vk.into()
74    }
75}
76
77impl AsRef<[u8]> for SigningKey {
78    fn as_ref(&self) -> &[u8] {
79        &self.seed[..]
80    }
81}
82
83impl From<SigningKey> for [u8; 32] {
84    fn from(sk: SigningKey) -> [u8; 32] {
85        sk.seed
86    }
87}
88
89impl TryFrom<&[u8]> for SigningKey {
90    type Error = Error;
91    fn try_from(slice: &[u8]) -> Result<SigningKey, Self::Error> {
92        if slice.len() == 32 {
93            let mut bytes = [0u8; 32];
94            bytes[..].copy_from_slice(slice);
95            Ok(bytes.into())
96        } else {
97            Err(Self::Error::InvalidSliceLength)
98        }
99    }
100}
101
102impl From<[u8; 32]> for SigningKey {
103    #[allow(non_snake_case)]
104    fn from(seed: [u8; 32]) -> SigningKey {
105        // Expand the seed to a 64-byte array with SHA512.
106        let h = Sha512::digest(&seed[..]);
107
108        // Convert the low half to a scalar with Ed25519 "clamping"
109        let s = {
110            let mut scalar_bytes = [0u8; 32];
111            scalar_bytes[..].copy_from_slice(&h.as_slice()[0..32]);
112            scalar_bytes[0] &= 248;
113            scalar_bytes[31] &= 127;
114            scalar_bytes[31] |= 64;
115            Scalar::from_bytes_mod_order(scalar_bytes)
116        };
117
118        // Extract and cache the high half.
119        let prefix = {
120            let mut prefix = [0u8; 32];
121            prefix[..].copy_from_slice(&h.as_slice()[32..64]);
122            prefix
123        };
124
125        // Compute the public key as A = [s]B.
126        let A = &s * constants::ED25519_BASEPOINT_TABLE;
127
128        SigningKey {
129            seed,
130            s,
131            prefix,
132            vk: VerificationKey {
133                minus_A: -A,
134                A_bytes: VerificationKeyBytes(A.compress().to_bytes()),
135            },
136        }
137    }
138}
139
140#[cfg(feature = "pkcs8")]
141impl<'a> TryFrom<PrivateKeyInfo<'a>> for SigningKey {
142    type Error = Error;
143    fn try_from(pki: PrivateKeyInfo) -> Result<Self, Self::Error> {
144        if pki.algorithm == ALGORITHM_ID {
145            SigningKey::try_from(pki.private_key)
146        } else {
147            Err(Self::Error::MalformedSecretKey)
148        }
149    }
150}
151
152#[cfg(feature = "pkcs8")]
153impl EncodePublicKey for SigningKey {
154    /// Serialize the public key for a [`SigningKey`] to an ASN.1 DER-encoded document.
155    fn to_public_key_der(&self) -> pkcs8::spki::Result<Document> {
156        self.vk.to_public_key_der()
157    }
158}
159
160impl Signer<Signature> for SigningKey {
161    /// Generate a [`Signature`] using a given [`SigningKey`].
162    fn try_sign(&self, message: &[u8]) -> Result<Signature, ed25519::signature::Error> {
163        Ok(self.sign(message))
164    }
165}
166
167#[cfg(feature = "pkcs8")]
168impl TryFrom<KeypairBytes> for SigningKey {
169    type Error = pkcs8::Error;
170
171    fn try_from(pkcs8_key: KeypairBytes) -> pkcs8::Result<Self> {
172        SigningKey::try_from(&pkcs8_key)
173    }
174}
175
176#[cfg(feature = "pkcs8")]
177impl TryFrom<&KeypairBytes> for SigningKey {
178    type Error = pkcs8::Error;
179
180    fn try_from(pkcs8_key: &KeypairBytes) -> pkcs8::Result<Self> {
181        let signing_key = SigningKey::from_der(&pkcs8_key.secret_key);
182
183        // Validate the public key in the PKCS#8 document if present
184        if let Some(public_bytes) = &pkcs8_key.public_key {
185            let expected_verifying_key =
186                VerificationKey::from_public_key_der(public_bytes.as_ref())
187                    .map_err(|_| pkcs8::Error::KeyMalformed)?;
188
189            if VerificationKey::try_from(&signing_key.unwrap())
190                .unwrap()
191                .A_bytes
192                != expected_verifying_key.into()
193            {
194                return Err(pkcs8::Error::KeyMalformed);
195            }
196        }
197
198        signing_key
199    }
200}
201
202#[cfg(feature = "pem")]
203impl From<SigningKey> for KeypairBytes {
204    fn from(signing_key: SigningKey) -> KeypairBytes {
205        KeypairBytes::from(&signing_key)
206    }
207}
208
209#[cfg(feature = "pem")]
210impl From<&SigningKey> for KeypairBytes {
211    fn from(signing_key: &SigningKey) -> KeypairBytes {
212        KeypairBytes {
213            secret_key: signing_key.s.to_bytes(),
214            public_key: Some(PublicKeyBytes(signing_key.vk.try_into().unwrap())),
215        }
216    }
217}
218
219#[cfg(feature = "pkcs8")]
220impl EncodePrivateKey for SigningKey {
221    /// Serialize [`SigningKey`] to an ASN.1 DER-encoded secret document. Note that this
222    /// will generate a v2 (RFC 5958) DER encoding with a public key.
223    fn to_pkcs8_der(&self) -> pkcs8::Result<SecretDocument> {
224        // In RFC 8410, the octet string containing the private key is encapsulated by
225        // another octet string. Just add octet string bytes to the key when building
226        // the document.
227        let mut final_key = [0u8; 34];
228        final_key[..2].copy_from_slice(&[0x04, 0x20]);
229        final_key[2..].copy_from_slice(&self.seed);
230        SecretDocument::try_from(PrivateKeyInfo {
231            algorithm: ALGORITHM_ID,
232            private_key: &final_key,
233            public_key: Some(self.vk.A_bytes.0.as_slice()),
234        })
235    }
236}
237
238#[cfg(feature = "pkcs8")]
239impl DecodePrivateKey for SigningKey {
240    /// Create a [`SigningKey`] from an ASN.1 DER-encoded bytes. The bytes may include an
241    /// accompanying public key, as defined in RFC 5958 (v1 and v2), but the call will
242    /// fail if the public key doesn't match the private key's true accompanying public
243    /// key.
244    fn from_pkcs8_der(bytes: &[u8]) -> pkcs8::Result<Self> {
245        let keypair = KeypairBytes::from_pkcs8_der(bytes).unwrap();
246        let sk = SigningKey::try_from(keypair.secret_key).unwrap();
247        match keypair.public_key {
248            Some(vk2) => {
249                if sk.vk.A_bytes.0 == vk2.to_bytes() {
250                    Ok(sk)
251                } else {
252                    Err(pkcs8::Error::KeyMalformed)
253                }
254            }
255            None => Ok(sk),
256        }
257    }
258}
259
260#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
261struct SerdeHelper([u8; 32]);
262
263impl From<SerdeHelper> for SigningKey {
264    fn from(helper: SerdeHelper) -> SigningKey {
265        helper.0.into()
266    }
267}
268
269impl From<SigningKey> for SerdeHelper {
270    fn from(sk: SigningKey) -> Self {
271        Self(sk.into())
272    }
273}
274
275impl SigningKey {
276    /// Generate a new signing key.
277    pub fn new<R: RngCore + CryptoRng>(mut rng: R) -> SigningKey {
278        let mut bytes = [0u8; 32];
279        rng.fill_bytes(&mut bytes[..]);
280        bytes.into()
281    }
282
283    /// Create a signature on `msg` using this key.
284    #[allow(non_snake_case)]
285    pub fn sign(&self, msg: &[u8]) -> Signature {
286        let r = Scalar::from_hash(Sha512::default().chain(&self.prefix[..]).chain(msg));
287
288        let R_bytes = (&r * constants::ED25519_BASEPOINT_TABLE)
289            .compress()
290            .to_bytes();
291
292        let k = Scalar::from_hash(
293            Sha512::default()
294                .chain(&R_bytes[..])
295                .chain(&self.vk.A_bytes.0[..])
296                .chain(msg),
297        );
298
299        let s_bytes = (r + k * self.s).to_bytes();
300
301        Signature::from_components(R_bytes, s_bytes)
302    }
303
304    /// Parse [`SigningKey`] from ASN.1 DER bytes.
305    #[cfg(feature = "pkcs8")]
306    pub fn from_der(bytes: &[u8]) -> pkcs8::Result<Self> {
307        bytes
308            .try_into()
309            .map_err(|_| pkcs8::Error::ParametersMalformed)
310    }
311
312    /// Serialize [`SigningKey`] to an ASN.1 DER-encoded secret document. Note that this
313    /// will generate a v1 (RFC 5958) DER encoding without a public key.
314    #[cfg(feature = "pkcs8")]
315    pub fn to_pkcs8_der_v1(&self) -> pkcs8::Result<SecretDocument> {
316        // In RFC 8410, the octet string containing the private key is encapsulated by
317        // another octet string. Just add octet string bytes to the key when building
318        // the document.
319        let mut final_key = [0u8; 34];
320        final_key[..2].copy_from_slice(&[0x04, 0x20]);
321        final_key[2..].copy_from_slice(&self.seed);
322        SecretDocument::try_from(PrivateKeyInfo::new(ALGORITHM_ID, &final_key))
323    }
324
325    /// Serialize [`SigningKey`] as a PEM-encoded PKCS#8 string. Note that this
326    /// will generate a v1 (RFC 5958) PEM encoding without a public key.
327    #[cfg(all(feature = "pem", feature = "pkcs8"))]
328    pub fn to_pkcs8_pem_v1(
329        &self,
330        line_ending: LineEnding,
331    ) -> Result<Zeroizing<String>, pkcs8::Error> {
332        let doc = self.to_pkcs8_der_v1()?;
333        Ok(doc.to_pem(PrivateKeyInfo::PEM_LABEL, line_ending)?)
334    }
335}