Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions src/pczt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}

Expand Down
25 changes: 24 additions & 1 deletion src/pczt/signer.rs
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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<SpendAuth>,
) -> 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.
Expand Down
Loading