xpx_chain_crypto/
secret.rs

1// Copyright 2018 ProximaX Limited. All rights reserved.
2// Use of this source code is governed by the Apache 2.0
3// license that can be found in the LICENSE file.
4
5//! ed25519 secret key types.
6
7use core::fmt::Debug;
8use std::vec::Vec;
9
10use clear_on_drop::clear::Clear;
11
12use curve25519_dalek::constants;
13use curve25519_dalek::digest::generic_array::typenum::U64;
14use curve25519_dalek::digest::Digest;
15use curve25519_dalek::edwards::CompressedEdwardsY;
16use curve25519_dalek::scalar::Scalar;
17
18use rand::CryptoRng;
19use rand::Rng;
20
21use sha3::Sha3_512;
22
23#[cfg(feature = "serde")]
24use serde::de::Error as SerdeError;
25#[cfg(feature = "serde")]
26use serde::de::Visitor;
27#[cfg(feature = "serde")]
28use serde::{Deserialize, Serialize};
29#[cfg(feature = "serde")]
30use serde::{Deserializer, Serializer};
31
32use crate::constants::*;
33use crate::errors::*;
34use crate::public::*;
35use crate::signature::*;
36
37/// An EdDSA secret key.
38#[derive(Default, Clone)] // we derive Default in order to use the clear() method in Drop
39pub struct SecretKey(pub(crate) [u8; SECRET_KEY_LENGTH]);
40
41impl Debug for SecretKey {
42    fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
43        write!(f, "SecretKey: {:?}", &self.0[..])
44    }
45}
46
47/// Overwrite secret key material with null bytes when it goes out of scope.
48impl Drop for SecretKey {
49    fn drop(&mut self) {
50        self.0.clear();
51    }
52}
53
54impl AsRef<[u8]> for SecretKey {
55    fn as_ref(&self) -> &[u8] {
56        self.as_bytes()
57    }
58}
59
60impl SecretKey {
61    /// Convert this secret key to a byte array.
62    #[inline]
63    pub fn to_bytes(&self) -> [u8; SECRET_KEY_LENGTH] {
64        self.0
65    }
66
67    /// View this secret key as a byte array.
68    #[inline]
69    pub fn as_bytes(&self) -> &[u8; SECRET_KEY_LENGTH] {
70        &self.0
71    }
72
73    /// Construct a `SecretKey` from a slice of bytes.
74    ///
75    /// # Example
76    ///
77    /// ```
78    /// # extern crate xpx_chain_crypto;
79    /// #
80    /// use xpx_chain_crypto::SecretKey;
81    /// use xpx_chain_crypto::SECRET_KEY_LENGTH;
82    /// use xpx_chain_crypto::SignatureError;
83    ///
84    /// # fn doctest() -> Result<SecretKey, SignatureError> {
85    /// let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = [
86    ///    157, 097, 177, 157, 239, 253, 090, 096,
87    ///    186, 132, 074, 244, 146, 236, 044, 196,
88    ///    068, 073, 197, 105, 123, 050, 105, 025,
89    ///    112, 059, 172, 003, 028, 174, 127, 096, ];
90    ///
91    /// let secret_key: SecretKey = SecretKey::from_bytes(secret_key_bytes.to_vec())?;
92    /// #
93    /// # Ok(secret_key)
94    /// # }
95    /// #
96    /// # fn main() {
97    /// #     let result = doctest();
98    /// #     assert!(result.is_ok());
99    /// # }
100    /// ```
101    ///
102    /// # Returns
103    ///
104    /// A `Result` whose okay value is an EdDSA `SecretKey` or whose error value
105    /// is an `SignatureError` wrapping the internal error that occurred.
106    #[inline]
107    pub fn from_bytes(bytes: Vec<u8>) -> Result<SecretKey, SignatureError> {
108        if bytes.len() != SECRET_KEY_LENGTH {
109            return Err(SignatureError(InternalError::BytesLengthError {
110                name: "SecretKey",
111                length: SECRET_KEY_LENGTH,
112            }));
113        }
114        let mut bits: [u8; 32] = [0u8; 32];
115        bits.copy_from_slice(&bytes[..32]);
116
117        Ok(SecretKey(bits))
118    }
119
120    /// Generate a `SecretKey` from a `csprng`.
121    ///
122    /// # Example
123    ///
124    /// ```
125    /// extern crate rand;
126    /// extern crate sha3;
127    /// extern crate xpx_chain_crypto;
128    ///
129    /// # #[cfg(feature = "std")]
130    /// # fn main() {
131    /// #
132    /// use rand::Rng;
133    /// use rand::rngs::OsRng;
134    /// use sha3::Sha3_512;
135    /// use xpx_chain_crypto::PublicKey;
136    /// use xpx_chain_crypto::SecretKey;
137    /// use xpx_chain_crypto::Signature;
138    ///
139    /// let mut csprng = OsRng{};
140    /// let secret_key: SecretKey = SecretKey::generate(&mut csprng);
141    /// # }
142    /// #
143    /// # #[cfg(not(feature = "std"))]
144    /// # fn main() { }
145    /// ```
146    ///
147    /// Afterwards, you can generate the corresponding public:
148    ///
149    /// ```
150    /// # extern crate rand;
151    /// # extern crate xpx_chain_crypto;
152    /// #
153    /// # fn main() {
154    /// #
155    /// # use rand::Rng;
156    /// # use rand::thread_rng;
157    /// # use xpx_chain_crypto::PublicKey;
158    /// # use xpx_chain_crypto::SecretKey;
159    /// # use xpx_chain_crypto::Signature;
160    /// #
161    /// # let mut csprng = thread_rng();
162    /// # let secret_key: SecretKey = SecretKey::generate(&mut csprng);
163    ///
164    /// let public_key: PublicKey = (&secret_key).into();
165    /// # }
166    /// ```
167    ///
168    /// # Input
169    ///
170    /// A CSPRNG with a `fill_bytes()` method, e.g. `rand::OsRng`
171    pub fn generate<T>(csprng: &mut T) -> SecretKey
172    where
173        T: CryptoRng + Rng,
174    {
175        let mut sk: SecretKey = SecretKey([0u8; 32]);
176
177        csprng.fill_bytes(&mut sk.0);
178
179        sk
180    }
181}
182
183#[cfg(feature = "serde")]
184impl Serialize for SecretKey {
185    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
186    where
187        S: Serializer,
188    {
189        serializer.serialize_bytes(self.as_bytes())
190    }
191}
192
193#[cfg(feature = "serde")]
194impl<'d> Deserialize<'d> for SecretKey {
195    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
196    where
197        D: Deserializer<'d>,
198    {
199        struct SecretKeyVisitor;
200
201        impl<'d> Visitor<'d> for SecretKeyVisitor {
202            type Value = SecretKey;
203
204            fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
205                formatter.write_str("An ed25519 secret key as 32 bytes, as specified in RFC8032.")
206            }
207
208            fn visit_bytes<E>(self, bytes: &[u8]) -> Result<SecretKey, E>
209            where
210                E: SerdeError,
211            {
212                SecretKey::from_bytes(bytes.to_vec()).or(Err(SerdeError::invalid_length(bytes.len(), &self)))
213            }
214        }
215        deserializer.deserialize_bytes(SecretKeyVisitor)
216    }
217}
218
219/// An "expanded" secret key.
220///
221/// This is produced by using an hash function with 512-bits output to digest a
222/// `SecretKey`.  The output digest is then split in half, the lower half being
223/// the actual `key` used to sign messages, after twiddling with some bits.¹ The
224/// upper half is used a sort of half-baked, ill-designed² pseudo-domain-separation
225/// "nonce"-like thing, which is used during signature production by
226/// concatenating it with the message to be signed before the message is hashed.
227//
228// ¹ This results in a slight bias towards non-uniformity at one spectrum of
229// the range of valid keys.  Oh well: not my idea; not my problem.
230//
231// ² It is the author's view (specifically, isis agora lovecruft, in the event
232// you'd like to complain about me, again) that this is "ill-designed" because
233// this doesn't actually provide true hash domain separation, in that in many
234// real-world applications a user wishes to have one key which is used in
235// several contexts (such as within tor, which does does domain separation
236// manually by pre-concatenating static strings to messages to achieve more
237// robust domain separation).  In other real-world applications, such as
238// bitcoind, a user might wish to have one master keypair from which others are
239// derived (à la BIP32) and different domain separators between keys derived at
240// different levels (and similarly for tree-based key derivation constructions,
241// such as hash-based signatures).  Leaving the domain separation to
242// application designers, who thus far have produced incompatible,
243// slightly-differing, ad hoc domain separation (at least those application
244// designers who knew enough cryptographic theory to do so!), is therefore a
245// bad design choice on the part of the cryptographer designing primitives
246// which should be simple and as foolproof as possible to use for
247// non-cryptographers.  Further, later in the ed25519 signature scheme, as
248// specified in RFC8032, the public key is added into *another* hash digest
249// (along with the message, again); it is unclear to this author why there's
250// not only one but two poorly-thought-out attempts at domain separation in the
251// same signature scheme, and which both fail in exactly the same way.  For a
252// better-designed, Schnorr-based signature scheme, see Trevor Perrin's work on
253// "generalised EdDSA" and "VXEdDSA".
254#[derive(Default)] // we derive Default in order to use the clear() method in Drop
255pub struct ExpandedSecretKey {
256    pub(crate) key: Scalar,
257    pub(crate) nonce: [u8; 32],
258}
259
260/// Overwrite secret key material with null bytes when it goes out of scope.
261impl Drop for ExpandedSecretKey {
262    fn drop(&mut self) {
263        self.key.clear();
264        self.nonce.clear();
265    }
266}
267
268impl<'a> From<&'a SecretKey> for ExpandedSecretKey {
269    /// Construct an `ExpandedSecretKey` from a `SecretKey`.
270    ///
271    /// # Examples
272    ///
273    /// ```
274    /// # extern crate rand;
275    /// # extern crate sha3;
276    /// # extern crate xpx_chain_crypto;
277    /// #
278    /// # fn main() {
279    /// #
280    /// use rand::Rng;
281    /// use rand::thread_rng;
282    /// use sha3::Sha3_512;
283    /// use xpx_chain_crypto::{SecretKey, ExpandedSecretKey};
284    ///
285    /// let mut csprng = thread_rng();
286    /// let secret_key: SecretKey = SecretKey::generate(&mut csprng);
287    /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key);
288    /// # }
289    /// ```
290    fn from(secret_key: &'a SecretKey) -> ExpandedSecretKey {
291        let mut h: Sha3_512 = Sha3_512::default();
292        let mut hash: [u8; 64] = [0u8; 64];
293        let mut lower: [u8; 32] = [0u8; 32];
294        let mut upper: [u8; 32] = [0u8; 32];
295
296        let secret_key = secret_key.to_bytes();
297        h.update(secret_key);
298        hash.copy_from_slice(h.finalize().as_slice());
299
300        lower.copy_from_slice(&hash[00..32]);
301        upper.copy_from_slice(&hash[32..64]);
302
303        lower[0] &= 248;
304        lower[31] &= 127;
305        lower[31] |= 64;
306
307        ExpandedSecretKey {
308            key: Scalar::from_bits(lower),
309            nonce: upper,
310        }
311    }
312}
313
314impl ExpandedSecretKey {
315    /// Convert this `ExpandedSecretKey` into an array of 64 bytes.
316    ///
317    /// # Returns
318    ///
319    /// An array of 64 bytes.  The first 32 bytes represent the "expanded"
320    /// secret key, and the last 32 bytes represent the "domain-separation"
321    /// "nonce".
322    ///
323    /// # Examples
324    ///
325    /// ```
326    /// # extern crate rand;
327    /// # extern crate sha3;
328    /// # extern crate xpx_chain_crypto;
329    /// #
330    /// # #[cfg(all(feature = "sha3", feature = "std"))]
331    /// # fn main() {
332    /// #
333    /// use rand::Rng;
334    /// use rand::rngs::OsRng;
335    /// use sha3::Sha3_512;
336    /// use xpx_chain_crypto::{SecretKey, ExpandedSecretKey};
337    ///
338    /// let mut csprng = OsRng{};
339    /// let secret_key: SecretKey = SecretKey::generate(&mut csprng);
340    /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key);
341    /// let expanded_secret_key_bytes: [u8; 64] = expanded_secret_key.to_bytes();
342    ///
343    /// assert!(&expanded_secret_key_bytes[..] != &[0u8; 64][..]);
344    /// # }
345    /// #
346    /// # #[cfg(any(not(feature = "sha3"), not(feature = "std")))]
347    /// # fn main() { }
348    /// ```
349    #[inline]
350    pub fn to_bytes(&self) -> [u8; EXPANDED_SECRET_KEY_LENGTH] {
351        let mut bytes: [u8; 64] = [0u8; 64];
352
353        bytes[..32].copy_from_slice(self.key.as_bytes());
354        bytes[32..].copy_from_slice(&self.nonce[..]);
355        bytes
356    }
357
358    /// Construct an `ExpandedSecretKey` from a slice of bytes.
359    ///
360    /// # Returns
361    ///
362    /// A `Result` whose okay value is an EdDSA `ExpandedSecretKey` or whose
363    /// error value is an `SignatureError` describing the error that occurred.
364    ///
365    /// # Examples
366    ///
367    /// ```
368    /// # extern crate rand;
369    /// # extern crate sha3;
370    /// # extern crate xpx_chain_crypto;
371    /// #
372    /// # use xpx_chain_crypto::{ExpandedSecretKey, SignatureError};
373    /// #
374    /// # #[cfg(all(feature = "sha3", feature = "std"))]
375    /// # fn do_test() -> Result<ExpandedSecretKey, SignatureError> {
376    /// #
377    /// use rand::Rng;
378    /// use rand::rngs::OsRng;
379    /// use xpx_chain_crypto::{SecretKey, ExpandedSecretKey};
380    /// use xpx_chain_crypto::SignatureError;
381    ///
382    /// let mut csprng = OsRng{};
383    /// let secret_key: SecretKey = SecretKey::generate(&mut csprng);
384    /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key);
385    /// let bytes: [u8; 64] = expanded_secret_key.to_bytes();
386    /// let expanded_secret_key_again = ExpandedSecretKey::from_bytes(&bytes)?;
387    /// #
388    /// # Ok(expanded_secret_key_again)
389    /// # }
390    /// #
391    /// # #[cfg(all(feature = "sha3", feature = "std"))]
392    /// # fn main() {
393    /// #     let result = do_test();
394    /// #     assert!(result.is_ok());
395    /// # }
396    /// #
397    /// # #[cfg(any(not(feature = "sha3"), not(feature = "std")))]
398    /// # fn main() { }
399    /// ```
400    #[inline]
401    pub fn from_bytes(bytes: &[u8]) -> Result<ExpandedSecretKey, SignatureError> {
402        if bytes.len() != EXPANDED_SECRET_KEY_LENGTH {
403            return Err(SignatureError(InternalError::BytesLengthError {
404                name: "ExpandedSecretKey",
405                length: EXPANDED_SECRET_KEY_LENGTH,
406            }));
407        }
408        let mut lower: [u8; 32] = [0u8; 32];
409        let mut upper: [u8; 32] = [0u8; 32];
410
411        lower.copy_from_slice(&bytes[00..32]);
412        upper.copy_from_slice(&bytes[32..64]);
413
414        Ok(ExpandedSecretKey {
415            key: Scalar::from_bits(lower),
416            nonce: upper,
417        })
418    }
419
420    /// Sign a message with this `ExpandedSecretKey`.
421    #[allow(non_snake_case)]
422    pub fn sign(&self, message: &[u8], public_key: &PublicKey) -> Signature {
423        let mut h: Sha3_512 = Sha3_512::new();
424        let R: CompressedEdwardsY;
425        let r: Scalar;
426        let s: Scalar;
427        let k: Scalar;
428
429        h.update(&self.nonce);
430        h.update(&message);
431
432        r = Scalar::from_hash(h);
433        R = (&r * &constants::ED25519_BASEPOINT_TABLE).compress();
434
435        h = Sha3_512::new();
436        h.update(R.as_bytes());
437        h.update(public_key.as_bytes());
438        h.update(&message);
439
440        k = Scalar::from_hash(h);
441        s = &(&k * &self.key) + &r;
442
443        Signature { R, s }
444    }
445
446    /// Sign a `prehashed_message` with this `ExpandedSecretKey` using the
447    /// Ed25519ph algorithm defined in [RFC8032 §5.1][rfc8032].
448    ///
449    /// # Inputs
450    ///
451    /// * `prehashed_message` is an instantiated hash digest with 512-bits of
452    ///   output which has had the message to be signed previously fed into its
453    ///   state.
454    /// * `public_key` is a [`PublicKey`] which corresponds to this secret key.
455    /// * `context` is an optional context string, up to 255 bytes inclusive,
456    ///   which may be used to provide additional domain separation.  If not
457    ///   set, this will default to an empty string.
458    ///
459    /// # Returns
460    ///
461    /// An Ed25519ph [`Signature`] on the `prehashed_message`.
462    ///
463    /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1
464    #[allow(non_snake_case)]
465    pub fn sign_prehashed<D>(
466        &self,
467        prehashed_message: D,
468        public_key: &PublicKey,
469        context: Option<&'static [u8]>,
470    ) -> Signature
471    where
472        D: Digest<OutputSize = U64>,
473    {
474        let mut h: Sha3_512;
475        let mut prehash: [u8; 64] = [0u8; 64];
476        let R: CompressedEdwardsY;
477        let r: Scalar;
478        let s: Scalar;
479        let k: Scalar;
480
481        let ctx: &[u8] = context.unwrap_or(b""); // By default, the context is an empty string.
482
483        debug_assert!(
484            ctx.len() <= 255,
485            "The context must not be longer than 255 octets."
486        );
487
488        let ctx_len: u8 = ctx.len() as u8;
489
490        // Get the result of the pre-hashed message.
491        prehash.copy_from_slice(prehashed_message.finalize().as_slice());
492
493        // This is the dumbest, ten-years-late, non-admission of fucking up the
494        // domain separation I have ever seen.  Why am I still required to put
495        // the upper half "prefix" of the hashed "secret key" in here?  Why
496        // can't the user just supply their own nonce and decide for themselves
497        // whether or not they want a deterministic signature scheme?  Why does
498        // the message go into what's ostensibly the signature domain separation
499        // hash?  Why wasn't there always a way to provide a context string?
500        //
501        // ...
502        //
503        // This is a really fucking stupid bandaid, and the damned scheme is
504        // still bleeding from malleability, for fuck's sake.
505        h = Sha3_512::new()
506            .chain(b"SigEd25519 no Ed25519 collisions")
507            .chain(&[1]) // Ed25519ph
508            .chain(&[ctx_len])
509            .chain(ctx)
510            .chain(&self.nonce)
511            .chain(&prehash[..]);
512
513        r = Scalar::from_hash(h);
514        R = (&r * &constants::ED25519_BASEPOINT_TABLE).compress();
515
516        h = Sha3_512::new()
517            .chain(b"SigEd25519 no Ed25519 collisions")
518            .chain(&[1]) // Ed25519ph
519            .chain(&[ctx_len])
520            .chain(ctx)
521            .chain(R.as_bytes())
522            .chain(public_key.as_bytes())
523            .chain(&prehash[..]);
524
525        k = Scalar::from_hash(h);
526        s = &(&k * &self.key) + &r;
527
528        Signature { R, s }
529    }
530}
531
532#[cfg(feature = "serde")]
533impl Serialize for ExpandedSecretKey {
534    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
535    where
536        S: Serializer,
537    {
538        serializer.serialize_bytes(&self.to_bytes()[..])
539    }
540}
541
542#[cfg(feature = "serde")]
543impl<'d> Deserialize<'d> for ExpandedSecretKey {
544    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
545    where
546        D: Deserializer<'d>,
547    {
548        struct ExpandedSecretKeyVisitor;
549
550        impl<'d> Visitor<'d> for ExpandedSecretKeyVisitor {
551            type Value = ExpandedSecretKey;
552
553            fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
554                formatter.write_str(
555                    "An ed25519 expanded secret key as 64 bytes, as specified in RFC8032.",
556                )
557            }
558
559            fn visit_bytes<E>(self, bytes: &[u8]) -> Result<ExpandedSecretKey, E>
560            where
561                E: SerdeError,
562            {
563                ExpandedSecretKey::from_bytes(bytes)
564                    .or(Err(SerdeError::invalid_length(bytes.len(), &self)))
565            }
566        }
567        deserializer.deserialize_bytes(ExpandedSecretKeyVisitor)
568    }
569}