sapling_crypto/pczt/
signer.rs1use core::fmt;
2
3use rand::{CryptoRng, RngCore};
4use redjubjub::SpendAuth;
5
6use crate::keys::SpendAuthorizingKey;
7
8impl super::Spend {
9 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 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#[derive(Debug)]
54#[non_exhaustive]
55pub enum SignerError {
56 InvalidExternalSignature,
58 MissingSpendAuthRandomizer,
60 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 {}