From 35a76f03b8bb6e48bf9b0a23266aee2db4e41068 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 21 Jun 2022 02:39:34 +0000 Subject: [PATCH] Add `orchard::bundle::BatchValidator` Adapted from the `BatchValidator` in `zcashd`, that only handles RedPallas signatures. --- CHANGELOG.md | 3 ++ Cargo.toml | 3 ++ src/bundle.rs | 3 ++ src/bundle/batch.rs | 74 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 83 insertions(+) create mode 100644 src/bundle/batch.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index e7dc93fd..b527d10c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ and this project adheres to Rust's notion of [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- `orchard::bundle::BatchValidator` + ### Changed - Migrated to `halo2_proofs 0.2`. diff --git a/Cargo.toml b/Cargo.toml index 6dc303ba..7f1cd8f5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,6 +44,9 @@ subtle = "2.3" zcash_note_encryption = "0.1" incrementalmerkletree = "0.3" +# Logging +tracing = "0.1" + # Developer tooling dependencies plotters = { version = "0.3.0", optional = true } diff --git a/src/bundle.rs b/src/bundle.rs index 5421dadc..c70ca635 100644 --- a/src/bundle.rs +++ b/src/bundle.rs @@ -1,7 +1,10 @@ //! Structs related to bundles of Orchard actions. +mod batch; pub mod commitments; +pub use batch::BatchValidator; + use core::fmt; use blake2b_simd::Hash as Blake2bHash; diff --git a/src/bundle/batch.rs b/src/bundle/batch.rs new file mode 100644 index 00000000..5bb462ac --- /dev/null +++ b/src/bundle/batch.rs @@ -0,0 +1,74 @@ +use rand::{CryptoRng, RngCore}; +use tracing::debug; + +use super::{Authorized, Bundle}; +use crate::primitives::redpallas::{self, Binding, SpendAuth}; + +/// A signature within an authorized Orchard bundle. +#[derive(Debug)] +struct BundleSignature { + /// The signature item for validation. + signature: redpallas::batch::Item, +} + +/// Batch validation context for Orchard. +/// +/// This batch-validates RedPallas signatures. +#[derive(Debug, Default)] +pub struct BatchValidator { + signatures: Vec, +} + +impl BatchValidator { + /// Constructs a new batch validation context. + pub fn new() -> Self { + BatchValidator { signatures: vec![] } + } + + /// Adds the RedPallas signatures from the given bundle to the validator. + pub fn add_bundle>( + &mut self, + bundle: &Bundle, + sighash: [u8; 32], + ) { + for action in bundle.actions().iter() { + self.signatures.push(BundleSignature { + signature: action + .rk() + .create_batch_item(action.authorization().clone(), &sighash), + }); + } + + self.signatures.push(BundleSignature { + signature: bundle + .binding_validating_key() + .create_batch_item(bundle.authorization().binding_signature().clone(), &sighash), + }); + } + + /// Batch-validates the accumulated bundles. + /// + /// Returns `true` if every signature in every bundle added to the batch validator is + /// valid, or `false` if one or more are invalid. No attempt is made to figure out + /// which of the accumulated bundles might be invalid; if that information is desired, + /// construct separate [`BatchValidator`]s for sub-batches of the bundles. + pub fn validate(&self, rng: R) -> bool { + if self.signatures.is_empty() { + // An empty batch is always valid, but is not free to run; skip it. + return true; + } + + let mut validator = redpallas::batch::Verifier::new(); + for sig in self.signatures.iter() { + validator.queue(sig.signature.clone()); + } + + match validator.verify(rng) { + Ok(()) => true, + Err(e) => { + debug!("RedPallas batch validation failed: {}", e); + false + } + } + } +}