decaf377_rdsa/
signing_key.rs

1use decaf377::Fr;
2use rand_core::{CryptoRng, RngCore};
3
4use crate::{Domain, Error, Signature, SpendAuth, VerificationKey};
5
6/// A `decaf377-rdsa` signing key.
7#[derive(Copy, Clone)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9#[cfg_attr(feature = "serde", serde(try_from = "SerdeHelper"))]
10#[cfg_attr(feature = "serde", serde(into = "SerdeHelper"))]
11#[cfg_attr(feature = "serde", serde(bound = "D: Domain"))]
12pub struct SigningKey<D: Domain> {
13    sk: Fr,
14    pk: VerificationKey<D>,
15}
16
17impl<'a, D: Domain> From<&'a SigningKey<D>> for VerificationKey<D> {
18    fn from(sk: &'a SigningKey<D>) -> VerificationKey<D> {
19        sk.pk.clone()
20    }
21}
22
23impl<'a, D: Domain> From<SigningKey<D>> for VerificationKey<D> {
24    fn from(sk: SigningKey<D>) -> VerificationKey<D> {
25        sk.pk.clone()
26    }
27}
28
29impl<D: Domain> From<SigningKey<D>> for [u8; 32] {
30    fn from(sk: SigningKey<D>) -> [u8; 32] {
31        sk.sk.to_bytes()
32    }
33}
34
35impl<D: Domain> SigningKey<D> {
36    /// Returns the byte encoding of the signing key.
37    ///
38    /// This is the same as `.into()`, but does not require type inference.
39    pub fn to_bytes(&self) -> [u8; 32] {
40        self.sk.to_bytes()
41    }
42}
43
44impl<D: Domain> TryFrom<[u8; 32]> for SigningKey<D> {
45    type Error = Error;
46
47    fn try_from(bytes: [u8; 32]) -> Result<Self, Self::Error> {
48        let sk = Fr::from_bytes_checked(&bytes).map_err(|_| Error::MalformedSigningKey)?;
49        Ok(Self::new_from_field(sk))
50    }
51}
52
53impl<D: Domain> TryFrom<&[u8]> for SigningKey<D> {
54    type Error = Error;
55
56    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
57        if bytes.len() == 32 {
58            let mut bytes32 = [0u8; 32];
59            bytes32.copy_from_slice(bytes);
60            bytes32.try_into()
61        } else {
62            Err(Error::WrongSliceLength {
63                expected: 32,
64                found: bytes.len(),
65            })
66        }
67    }
68}
69
70impl<D: Domain> From<Fr> for SigningKey<D> {
71    fn from(sk: Fr) -> Self {
72        Self::new_from_field(sk)
73    }
74}
75
76#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
77struct SerdeHelper([u8; 32]);
78
79impl<D: Domain> TryFrom<SerdeHelper> for SigningKey<D> {
80    type Error = Error;
81
82    fn try_from(helper: SerdeHelper) -> Result<Self, Self::Error> {
83        helper.0.try_into()
84    }
85}
86
87impl<D: Domain> From<SigningKey<D>> for SerdeHelper {
88    fn from(sk: SigningKey<D>) -> Self {
89        Self(sk.into())
90    }
91}
92
93impl SigningKey<SpendAuth> {
94    /// Randomize this public key with the given `randomizer`.
95    pub fn randomize(&self, randomizer: &Fr) -> SigningKey<SpendAuth> {
96        let sk = self.sk + randomizer;
97        let pk = VerificationKey::from(&sk);
98        SigningKey { sk, pk }
99    }
100}
101
102impl<D: Domain> SigningKey<D> {
103    /// Create a new signing key from the supplied `rng`.
104    pub fn new<R: RngCore + CryptoRng>(mut rng: R) -> SigningKey<D> {
105        let sk = {
106            let mut bytes = [0; 64];
107            rng.fill_bytes(&mut bytes);
108            Fr::from_le_bytes_mod_order(&bytes[..])
109        };
110        Self::new_from_field(sk)
111    }
112
113    /// Use the supplied field element as the signing key directly.
114    ///
115    /// # Warning
116    ///
117    /// This function exists to allow custom key derivation; it's the caller's
118    /// responsibility to ensure that the input was generated securely.
119    pub fn new_from_field(sk: Fr) -> SigningKey<D> {
120        let pk = VerificationKey::from(&sk);
121        SigningKey { sk, pk }
122    }
123
124    /// Create a signature for domain `D` on `msg` using this `SigningKey`.
125    // Similar to signature::Signer but without boxed errors.
126    pub fn sign<R: RngCore + CryptoRng>(&self, mut rng: R, msg: &[u8]) -> Signature<D> {
127        let mut bonus_randomness = [0u8; 48];
128        rng.fill_bytes(&mut bonus_randomness);
129        self.sign_inner(&bonus_randomness, msg)
130    }
131
132    /// Create a signature for domain `D` on `msg` using this `SigningKey`.
133    ///
134    /// Prefer `sign`, unless you know you need deterministic signatures.
135    pub fn sign_deterministic(&self, msg: &[u8]) -> Signature<D> {
136        let bonus_randomness = [0u8; 48];
137        self.sign_inner(&bonus_randomness, msg)
138    }
139
140    fn sign_inner(&self, bonus_randomness: &[u8; 48], msg: &[u8]) -> Signature<D> {
141        use crate::HStar;
142
143        // We deviate from RedDSA as specified in the Zcash protocol spec and instead
144        // use a construction in line with Trevor Perrin's synthetic nonces:
145        // https://moderncrypto.org/mail-archive/curves/2017/000925.html
146        // Rather than choosing T to be 80 random bytes (\ell_H + 128)/8 as in RedDSA,
147        // we choose T to be 32-byte sk || 48-byte bonus_randomness.
148        // In this way, even in the case of an RNG failure, we fall back to secure but
149        // deterministic signing.
150        let nonce = HStar::default()
151            .update(&self.sk.to_bytes()[..])
152            .update(&bonus_randomness[..])
153            .update(&self.pk.bytes.bytes[..]) // XXX ugly
154            .update(msg)
155            .finalize();
156
157        let r_bytes = (&D::basepoint() * &nonce).vartime_compress().0;
158
159        let c = HStar::default()
160            .update(&r_bytes[..])
161            .update(&self.pk.bytes.bytes[..]) // XXX ugly
162            .update(msg)
163            .finalize();
164
165        let s_bytes = (nonce + (c * self.sk)).to_bytes();
166
167        Signature::from_parts(r_bytes, s_bytes)
168    }
169}
170
171#[cfg(feature = "std")]
172mod std_only {
173    use super::*;
174    use std::fmt;
175
176    use crate::Binding;
177
178    impl fmt::Debug for SigningKey<Binding> {
179        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180            f.debug_tuple("SigningKey<Binding>")
181                .field(&hex::encode(&<[u8; 32]>::from(*self)))
182                .finish()
183        }
184    }
185
186    impl fmt::Debug for SigningKey<SpendAuth> {
187        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
188            f.debug_tuple("SigningKey<SpendAuth>")
189                .field(&hex::encode(&<[u8; 32]>::from(*self)))
190                .finish()
191        }
192    }
193}
194
195#[cfg(feature = "std")]
196pub use std_only::*;