Skip to content

Commit

Permalink
Add builder::PaddingRule for explicit control over output padding.
Browse files Browse the repository at this point in the history
  • Loading branch information
nuttycom committed Dec 13, 2023
1 parent dfc2442 commit 6fe24a1
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 9 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ The entries below are relative to the `zcash_primitives::sapling` module as of
- `SpendDescriptionInfo::value`
- `SaplingOutputInfo`
- `ProverProgress`
- `PaddingRule`
- `sapling_crypto::bundle` module:
- The following types moved from
`zcash_primitives::transaction::components::sapling`:
Expand Down Expand Up @@ -102,6 +103,10 @@ The entries below are relative to the `zcash_primitives::sapling` module as of
generic parameters and returns `(UnauthorizedBundle, SaplingMetadata)`. The
caller can then use `Bundle::<InProgress<Unproven, _>>::create_proofs` to
create spend and output proofs for the bundle.
- `SaplingBuilder::build` now takes a `PaddingRule` argument that instructs
it how to pad the bundle with dummy outputs.
- `SaplingBuilder::bundle_output_count` has been changed to use a padding
rule to compute its result.
- `Error` has new error variants:
- `Error::DuplicateSignature`
- `Error::InvalidExternalSignature`
Expand Down
49 changes: 40 additions & 9 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,36 @@ use crate::{
/// with dummy outputs if necessary. See <https://github.com/zcash/zcash/issues/3615>.
const MIN_SHIELDED_OUTPUTS: usize = 2;

/// An enumeration of rules for construction of dummy outputs that may be applied to Sapling bundle
/// construction.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum PaddingRule {
/// A rule that requires that at least the specified number of Sapling outputs is constructed,
/// irrespective of whether any genuine outputs are being included. If no padding is to be
/// performed, `Require(0)` may be used.
Require(usize),
/// A rule that requires that at least the specified number of Sapling outputs are constructed,
/// iff any genuine outputs are being included.
PadTo(usize),
}

impl PaddingRule {
pub const DEFAULT: PaddingRule = PaddingRule::PadTo(MIN_SHIELDED_OUTPUTS);

pub fn num_outputs(&self, real_outputs: usize) -> usize {
match self {
PaddingRule::Require(n) => std::cmp::max(real_outputs, *n),
PaddingRule::PadTo(n) => {
if real_outputs == 0 {
0
} else {
std::cmp::max(real_outputs, *n)
}
}
}
}
}

#[derive(Debug, PartialEq, Eq)]
pub enum Error {
AnchorMismatch,
Expand Down Expand Up @@ -318,12 +348,8 @@ impl SaplingBuilder {
///
/// This may be larger than the number of outputs that have been added to the builder,
/// depending on whether padding is going to be applied.
pub fn bundle_output_count(&self) -> usize {
// This matches the padding behaviour in `Self::build`.
match self.spends.len() {
0 => self.outputs.len(),
_ => std::cmp::max(MIN_SHIELDED_OUTPUTS, self.outputs.len()),
}
pub fn bundle_output_count(&self, padding_rule: PaddingRule) -> usize {
padding_rule.num_outputs(self.outputs.len())
}

/// Returns the net value represented by the spends and outputs added to this builder,
Expand Down Expand Up @@ -405,8 +431,10 @@ impl SaplingBuilder {
pub fn build<SP: SpendProver, OP: OutputProver, R: RngCore, V: TryFrom<i64>>(
self,
mut rng: R,
padding_rule: PaddingRule,
) -> Result<Option<(UnauthorizedBundle<V>, SaplingMetadata)>, Error> {
let value_balance = self.try_value_balance()?;
let bundle_output_count = self.bundle_output_count(padding_rule);

// Record initial positions of spends and outputs
let mut indexed_spends: Vec<_> = self.spends.into_iter().enumerate().collect();
Expand All @@ -425,7 +453,7 @@ impl SaplingBuilder {

// Pad Sapling outputs
if !indexed_spends.is_empty() {
while indexed_outputs.len() < MIN_SHIELDED_OUTPUTS {
while indexed_outputs.len() < bundle_output_count {
indexed_outputs.push(None);
}
}
Expand Down Expand Up @@ -876,7 +904,7 @@ pub mod testing {
frontier::testing::arb_commitment_tree, witness::IncrementalWitness,
};

use super::SaplingBuilder;
use super::{PaddingRule, SaplingBuilder};

#[allow(dead_code)]
fn arb_bundle<V: fmt::Debug + From<i64>>(
Expand Down Expand Up @@ -913,7 +941,10 @@ pub mod testing {
}

let (bundle, _) = builder
.build::<MockSpendProver, MockOutputProver, _, _>(&mut rng)
.build::<MockSpendProver, MockOutputProver, _, _>(
&mut rng,
PaddingRule::DEFAULT,
)
.unwrap()
.unwrap();

Expand Down

0 comments on commit 6fe24a1

Please sign in to comment.