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 11, 2023
1 parent bea0286 commit ea72077
Showing 1 changed file with 41 additions and 9 deletions.
50 changes: 41 additions & 9 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,39 @@ 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.
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),
/// A padding rule that specifies that no additional dummy Sapling outputs are to be
/// constructed.
None,
}

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)
}
}
PaddingRule::None => real_outputs,
}
}
}

#[derive(Debug, PartialEq, Eq)]
pub enum Error {
AnchorMismatch,
Expand Down Expand Up @@ -289,16 +322,18 @@ pub struct SaplingBuilder {
spends: Vec<SpendDescriptionInfo>,
outputs: Vec<SaplingOutputInfo>,
zip212_enforcement: Zip212Enforcement,
padding_rule: PaddingRule,
}

impl SaplingBuilder {
pub fn new(zip212_enforcement: Zip212Enforcement) -> Self {
pub fn new(zip212_enforcement: Zip212Enforcement, padding_rule: PaddingRule) -> Self {
SaplingBuilder {
anchor: None,
value_balance: ValueSum::zero(),
spends: vec![],
outputs: vec![],
zip212_enforcement,
padding_rule,
}
}

Expand All @@ -319,11 +354,7 @@ 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()),
}
self.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 @@ -407,6 +438,7 @@ impl SaplingBuilder {
mut rng: R,
) -> Result<Option<(UnauthorizedBundle<V>, SaplingMetadata)>, Error> {
let value_balance = self.try_value_balance()?;
let bundle_output_count = self.bundle_output_count();

// Record initial positions of spends and outputs
let mut indexed_spends: Vec<_> = self.spends.into_iter().enumerate().collect();
Expand All @@ -425,7 +457,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 +908,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 All @@ -902,7 +934,7 @@ pub mod testing {
})
.prop_map(
move |(extsk, spendable_notes, commitment_trees, rng_seed, fake_sighash_bytes)| {
let mut builder = SaplingBuilder::new(zip212_enforcement);
let mut builder = SaplingBuilder::new(zip212_enforcement, PaddingRule::DEFAULT);
let mut rng = StdRng::from_seed(rng_seed);

for (note, path) in spendable_notes
Expand Down

0 comments on commit ea72077

Please sign in to comment.