diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ee564427..510f9d44b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,13 @@ and this project adheres to Rust's notion of ## [Unreleased] +### Added +- `orchard::pczt::Action::apply_signature` + +### Changed +- `orchard::pczt::SignerError` has added variants: + - `InvalidExternalSignature` + ## [0.11.0] - 2025-02-20 ### Added diff --git a/src/pczt.rs b/src/pczt.rs index 0f0de492f..e4872f900 100644 --- a/src/pczt.rs +++ b/src/pczt.rs @@ -480,6 +480,10 @@ mod tests { for action in pczt_bundle.actions_mut() { if action.spend.zip32_derivation.as_ref() == Some(&zip32_derivation) { action.sign(sighash, &ask, rng).unwrap(); + + // We can also apply the signature as an external signature. + let signature = action.spend().spend_auth_sig().clone().expect("signed"); + action.apply_signature(sighash, signature).unwrap(); } } diff --git a/src/pczt/signer.rs b/src/pczt/signer.rs index 7f5f8028c..4ba3480b5 100644 --- a/src/pczt/signer.rs +++ b/src/pczt/signer.rs @@ -1,6 +1,9 @@ use rand::{CryptoRng, RngCore}; -use crate::{keys::SpendAuthorizingKey, primitives::redpallas}; +use crate::{ + keys::SpendAuthorizingKey, + primitives::redpallas::{self, SpendAuth}, +}; impl super::Action { /// Signs the Orchard spend with the given spend authorizing key. @@ -29,11 +32,31 @@ impl super::Action { Err(SignerError::WrongSpendAuthorizingKey) } } + + /// Applies the given signature to the Orchard spend, if valid. + /// + /// It is the caller's responsibility to perform any semantic validity checks on the + /// PCZT (for example, comfirming that the change amounts are correct) before calling + /// this method. + pub fn apply_signature( + &mut self, + sighash: [u8; 32], + signature: redpallas::Signature, + ) -> Result<(), SignerError> { + if self.spend.rk.verify(&sighash, &signature).is_ok() { + self.spend.spend_auth_sig = Some(signature); + Ok(()) + } else { + Err(SignerError::InvalidExternalSignature) + } + } } /// Errors that can occur while signing an Orchard action in a PCZT. #[derive(Debug)] pub enum SignerError { + /// A provided external signature was not valid for the action's spend. + InvalidExternalSignature, /// The Signer role requires `alpha` to be set. MissingSpendAuthRandomizer, /// The provided `ask` does not own the action's spent note.