k256/schnorr/
signing.rs

1//! Taproot Schnorr signing key.
2
3use super::{tagged_hash, Signature, VerifyingKey, AUX_TAG, CHALLENGE_TAG, NONCE_TAG};
4use crate::{
5    AffinePoint, FieldBytes, NonZeroScalar, ProjectivePoint, PublicKey, Scalar, SecretKey,
6};
7use elliptic_curve::{
8    bigint::U256,
9    ops::Reduce,
10    rand_core::CryptoRngCore,
11    subtle::ConditionallySelectable,
12    zeroize::{Zeroize, ZeroizeOnDrop},
13};
14use sha2::{Digest, Sha256};
15use signature::{
16    digest::{consts::U32, FixedOutput},
17    hazmat::{PrehashSigner, RandomizedPrehashSigner},
18    DigestSigner, Error, KeypairRef, RandomizedDigestSigner, RandomizedSigner, Result, Signer,
19};
20
21#[cfg(feature = "serde")]
22use serdect::serde::{de, ser, Deserialize, Serialize};
23
24#[cfg(debug_assertions)]
25use signature::hazmat::PrehashVerifier;
26
27/// Taproot Schnorr signing key.
28#[derive(Clone)]
29pub struct SigningKey {
30    /// Secret key material
31    secret_key: NonZeroScalar,
32
33    /// Verifying key
34    verifying_key: VerifyingKey,
35}
36
37impl SigningKey {
38    /// Generate a cryptographically random [`SigningKey`].
39    pub fn random(rng: &mut impl CryptoRngCore) -> Self {
40        NonZeroScalar::random(rng).into()
41    }
42
43    /// Parse signing key from big endian-encoded bytes.
44    pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
45        NonZeroScalar::try_from(bytes)
46            .map(Into::into)
47            .map_err(|_| Error::new())
48    }
49
50    /// Serialize as bytes.
51    pub fn to_bytes(&self) -> FieldBytes {
52        self.secret_key.to_bytes()
53    }
54
55    /// Get the [`VerifyingKey`] that corresponds to this signing key.
56    pub fn verifying_key(&self) -> &VerifyingKey {
57        &self.verifying_key
58    }
59
60    /// Borrow the secret [`NonZeroScalar`] value for this key.
61    ///
62    /// # ⚠️ Warning
63    ///
64    /// This value is key material.
65    ///
66    /// Please treat it with the care it deserves!
67    pub fn as_nonzero_scalar(&self) -> &NonZeroScalar {
68        &self.secret_key
69    }
70
71    /// Compute Schnorr signature.
72    ///
73    /// # ⚠️  Warning
74    ///
75    /// This is a low-level interface intended only for unusual use cases
76    /// involving signing pre-hashed messages.
77    ///
78    /// The preferred interfaces are the [`Signer`] or [`RandomizedSigner`] traits.
79    pub fn sign_prehash_with_aux_rand(
80        &self,
81        msg_digest: &[u8; 32],
82        aux_rand: &[u8; 32],
83    ) -> Result<Signature> {
84        self.sign_raw(&msg_digest[..], &aux_rand)
85    }
86
87    /// Compute Schnorr signature.
88    ///
89    /// # ⚠️ Warning
90    ///
91    /// This is a low-level interface intended only for unusual use cases
92    /// involving signing pre-hashed messages, or "raw" messages where the
93    /// message is not hashed at all prior to being used to generate the
94    /// Schnorr signature.
95    ///
96    /// The preferred interfaces are the [`Signer`] or [`RandomizedSigner`] traits.
97    pub fn sign_raw(&self, msg: &[u8], aux_rand: &[u8; 32]) -> Result<Signature> {
98        let mut t = tagged_hash(AUX_TAG).chain_update(aux_rand).finalize();
99
100        for (a, b) in t.iter_mut().zip(self.secret_key.to_bytes().iter()) {
101            *a ^= b
102        }
103
104        let rand = tagged_hash(NONCE_TAG)
105            .chain_update(t)
106            .chain_update(self.verifying_key.as_affine().x.to_bytes())
107            .chain_update(msg)
108            .finalize();
109
110        let k = NonZeroScalar::try_from(&*rand)
111            .map(Self::from)
112            .map_err(|_| Error::new())?;
113
114        let secret_key = k.secret_key;
115        let verifying_point = AffinePoint::from(k.verifying_key);
116        let r = verifying_point.x.normalize();
117
118        let e = <Scalar as Reduce<U256>>::reduce_bytes(
119            &tagged_hash(CHALLENGE_TAG)
120                .chain_update(r.to_bytes())
121                .chain_update(self.verifying_key.to_bytes())
122                .chain_update(msg)
123                .finalize(),
124        );
125
126        let s = *secret_key + e * *self.secret_key;
127        let s = Option::from(NonZeroScalar::new(s)).ok_or_else(Error::new)?;
128        let sig = Signature { r, s };
129
130        #[cfg(debug_assertions)]
131        self.verifying_key.verify_prehash(msg, &sig)?;
132
133        Ok(sig)
134    }
135}
136
137impl From<NonZeroScalar> for SigningKey {
138    #[inline]
139    fn from(mut secret_key: NonZeroScalar) -> SigningKey {
140        let odd = (ProjectivePoint::GENERATOR * *secret_key)
141            .to_affine()
142            .y
143            .normalize()
144            .is_odd();
145
146        secret_key.conditional_assign(&-secret_key, odd);
147
148        let verifying_key = VerifyingKey {
149            inner: PublicKey::from_secret_scalar(&secret_key),
150        };
151
152        SigningKey {
153            secret_key,
154            verifying_key,
155        }
156    }
157}
158
159impl From<SecretKey> for SigningKey {
160    #[inline]
161    fn from(secret_key: SecretKey) -> SigningKey {
162        SigningKey::from(&secret_key)
163    }
164}
165
166impl From<&SecretKey> for SigningKey {
167    fn from(secret_key: &SecretKey) -> SigningKey {
168        secret_key.to_nonzero_scalar().into()
169    }
170}
171
172//
173// `*Signer` trait impls
174//
175
176impl<D> DigestSigner<D, Signature> for SigningKey
177where
178    D: Digest + FixedOutput<OutputSize = U32>,
179{
180    fn try_sign_digest(&self, digest: D) -> Result<Signature> {
181        self.sign_raw(&digest.finalize_fixed(), &Default::default())
182    }
183}
184
185impl PrehashSigner<Signature> for SigningKey {
186    fn sign_prehash(&self, prehash: &[u8]) -> Result<Signature> {
187        self.sign_raw(prehash, &Default::default())
188    }
189}
190
191impl<D> RandomizedDigestSigner<D, Signature> for SigningKey
192where
193    D: Digest + FixedOutput<OutputSize = U32>,
194{
195    fn try_sign_digest_with_rng(
196        &self,
197        rng: &mut impl CryptoRngCore,
198        digest: D,
199    ) -> Result<Signature> {
200        let mut aux_rand = [0u8; 32];
201        rng.fill_bytes(&mut aux_rand);
202        self.sign_raw(&digest.finalize_fixed(), &aux_rand)
203    }
204}
205
206impl RandomizedSigner<Signature> for SigningKey {
207    fn try_sign_with_rng(&self, rng: &mut impl CryptoRngCore, msg: &[u8]) -> Result<Signature> {
208        self.try_sign_digest_with_rng(rng, Sha256::new_with_prefix(msg))
209    }
210}
211
212impl RandomizedPrehashSigner<Signature> for SigningKey {
213    fn sign_prehash_with_rng(
214        &self,
215        rng: &mut impl CryptoRngCore,
216        prehash: &[u8],
217    ) -> Result<Signature> {
218        let mut aux_rand = [0u8; 32];
219        rng.fill_bytes(&mut aux_rand);
220
221        self.sign_raw(prehash, &aux_rand)
222    }
223}
224
225impl Signer<Signature> for SigningKey {
226    fn try_sign(&self, msg: &[u8]) -> Result<Signature> {
227        self.try_sign_digest(Sha256::new_with_prefix(msg))
228    }
229}
230
231//
232// Other trait impls
233//
234
235impl AsRef<VerifyingKey> for SigningKey {
236    fn as_ref(&self) -> &VerifyingKey {
237        &self.verifying_key
238    }
239}
240
241impl Drop for SigningKey {
242    fn drop(&mut self) {
243        self.secret_key.zeroize();
244    }
245}
246
247impl KeypairRef for SigningKey {
248    type VerifyingKey = VerifyingKey;
249}
250
251impl ZeroizeOnDrop for SigningKey {}
252
253#[cfg(feature = "serde")]
254impl Serialize for SigningKey {
255    fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
256    where
257        S: ser::Serializer,
258    {
259        self.secret_key.serialize(serializer)
260    }
261}
262
263#[cfg(feature = "serde")]
264impl<'de> Deserialize<'de> for SigningKey {
265    fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
266    where
267        D: de::Deserializer<'de>,
268    {
269        Ok(SigningKey::from(NonZeroScalar::deserialize(deserializer)?))
270    }
271}