sapling_crypto/pczt/
signer.rs

1use core::fmt;
2
3use rand::{CryptoRng, RngCore};
4use redjubjub::SpendAuth;
5
6use crate::keys::SpendAuthorizingKey;
7
8impl super::Spend {
9    /// Signs the Sapling spend with the given spend authorizing key.
10    ///
11    /// It is the caller's responsibility to perform any semantic validity checks on the
12    /// PCZT (for example, comfirming that the change amounts are correct) before calling
13    /// this method.
14    pub fn sign<R: RngCore + CryptoRng>(
15        &mut self,
16        sighash: [u8; 32],
17        ask: &SpendAuthorizingKey,
18        rng: R,
19    ) -> Result<(), SignerError> {
20        let alpha = self.alpha.ok_or(SignerError::MissingSpendAuthRandomizer)?;
21
22        let rsk = ask.randomize(&alpha);
23        let rk = redjubjub::VerificationKey::from(&rsk);
24
25        if self.rk == rk {
26            self.spend_auth_sig = Some(rsk.sign(rng, &sighash));
27            Ok(())
28        } else {
29            Err(SignerError::WrongSpendAuthorizingKey)
30        }
31    }
32
33    /// Applies the given signature to the Sapling spend, if valid.
34    ///
35    /// It is the caller's responsibility to perform any semantic validity checks on the
36    /// PCZT (for example, comfirming that the change amounts are correct) before calling
37    /// this method.
38    pub fn apply_signature(
39        &mut self,
40        sighash: [u8; 32],
41        signature: redjubjub::Signature<SpendAuth>,
42    ) -> Result<(), SignerError> {
43        if self.rk.verify(&sighash, &signature).is_ok() {
44            self.spend_auth_sig = Some(signature);
45            Ok(())
46        } else {
47            Err(SignerError::InvalidExternalSignature)
48        }
49    }
50}
51
52/// Errors that can occur while signing an Orchard action in a PCZT.
53#[derive(Debug)]
54#[non_exhaustive]
55pub enum SignerError {
56    /// A provided external signature was not valid for the spend.
57    InvalidExternalSignature,
58    /// The Signer role requires `alpha` to be set.
59    MissingSpendAuthRandomizer,
60    /// The provided `ask` does not own the spent note.
61    WrongSpendAuthorizingKey,
62}
63
64impl fmt::Display for SignerError {
65    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
66        match self {
67            SignerError::InvalidExternalSignature => {
68                write!(f, "External signature is invalid for the spend")
69            }
70            SignerError::MissingSpendAuthRandomizer => {
71                write!(f, "`alpha` must be set for the Signer role")
72            }
73            SignerError::WrongSpendAuthorizingKey => {
74                write!(f, "provided `ask` does not own the spent note")
75            }
76        }
77    }
78}
79
80#[cfg(feature = "std")]
81impl std::error::Error for SignerError {}