Skip to content

Commit

Permalink
Add explicit control of padding to the Builder API.
Browse files Browse the repository at this point in the history
  • Loading branch information
nuttycom committed Dec 8, 2023
1 parent 003619b commit 5ebf22d
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 16 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@ and this project adheres to Rust's notion of
## [Unreleased]

## [0.6.0] - 2023-09-08
### Added
- `orchard::builder::PaddingRule`

### Changed
- MSRV is now 1.65.0.
- Migrated to `incrementalmerkletree 0.5`.
- `orchard::builder::Builder::new` now takes an additional `PaddingRule` argument
that specifies how actions should be padded, instead of using hardcoded padding.

## [0.5.0] - 2023-06-06
### Changed
Expand Down
60 changes: 47 additions & 13 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,27 @@ use crate::{

const MIN_ACTIONS: usize = 2;

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

impl PaddingRule {
/// The default padding rule, which ensures that the constructed bundle will contain at least 2
/// actions if any genuine Orchard spends or outputs are requested.
pub const DEFAULT: PaddingRule = PaddingRule::PadTo(MIN_ACTIONS);
}

/// An error type for the kinds of errors that can occur during bundle construction.
#[derive(Debug)]
pub enum BuildError {
Expand Down Expand Up @@ -264,16 +285,18 @@ pub struct Builder {
recipients: Vec<RecipientInfo>,
flags: Flags,
anchor: Anchor,
padding_rule: PaddingRule,
}

impl Builder {
/// Constructs a new empty builder for an Orchard bundle.
pub fn new(flags: Flags, anchor: Anchor) -> Self {
pub fn new(flags: Flags, anchor: Anchor, padding_rule: PaddingRule) -> Self {
Builder {
spends: vec![],
recipients: vec![],
flags,
anchor,
padding_rule,
}
}

Expand Down Expand Up @@ -389,22 +412,31 @@ impl Builder {
mut self,
mut rng: impl RngCore,
) -> Result<Bundle<InProgress<Unproven, Unauthorized>, V>, BuildError> {
let num_real_spends = self.spends.len();
let num_real_recipients = self.recipients.len();
let num_real_actions = core::cmp::max(num_real_spends, num_real_recipients);

let num_actions = match self.padding_rule {
PaddingRule::Require(n) => core::cmp::max(num_real_actions, n),
PaddingRule::PadTo(n) => {
if num_real_actions == 0 {
0
} else {
core::cmp::max(num_real_actions, n)
}
}
PaddingRule::None => num_real_actions,
};

// Pair up the spends and recipients, extending with dummy values as necessary.
let pre_actions: Vec<_> = {
let num_spends = self.spends.len();
let num_recipients = self.recipients.len();
let num_actions = [num_spends, num_recipients, MIN_ACTIONS]
.iter()
.max()
.cloned()
.unwrap();

self.spends.extend(
iter::repeat_with(|| SpendInfo::dummy(&mut rng)).take(num_actions - num_spends),
iter::repeat_with(|| SpendInfo::dummy(&mut rng))
.take(num_actions - num_real_spends),
);
self.recipients.extend(
iter::repeat_with(|| RecipientInfo::dummy(&mut rng))
.take(num_actions - num_recipients),
.take(num_actions - num_real_recipients),
);

// Shuffle the spends and recipients, so that learning the position of a
Expand Down Expand Up @@ -777,7 +809,7 @@ pub mod testing {
Address, Note,
};

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

/// An intermediate type used for construction of arbitrary
/// bundle values. This type is required because of a limitation
Expand All @@ -801,7 +833,7 @@ pub mod testing {
fn into_bundle<V: TryFrom<i64>>(mut self) -> Bundle<Authorized, V> {
let fvk = FullViewingKey::from(&self.sk);
let flags = Flags::from_parts(true, true);
let mut builder = Builder::new(flags, self.anchor);
let mut builder = Builder::new(flags, self.anchor, PaddingRule::DEFAULT);

for (note, path) in self.notes.into_iter() {
builder.add_spend(fvk.clone(), note, path).unwrap();
Expand Down Expand Up @@ -899,6 +931,7 @@ mod tests {

use super::Builder;
use crate::{
builder::PaddingRule,
bundle::{Authorized, Bundle, Flags},
circuit::ProvingKey,
constants::MERKLE_DEPTH_ORCHARD,
Expand All @@ -919,6 +952,7 @@ mod tests {
let mut builder = Builder::new(
Flags::from_parts(true, true),
EMPTY_ROOTS[MERKLE_DEPTH_ORCHARD].into(),
PaddingRule::DEFAULT,
);

builder
Expand Down
7 changes: 4 additions & 3 deletions tests/builder.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use bridgetree::BridgeTree;
use incrementalmerkletree::Hashable;
use orchard::{
builder::Builder,
builder::{Builder, PaddingRule},
bundle::{Authorized, Flags},
circuit::{ProvingKey, VerifyingKey},
keys::{FullViewingKey, PreparedIncomingViewingKey, Scope, SpendAuthorizingKey, SpendingKey},
Expand Down Expand Up @@ -42,7 +42,8 @@ fn bundle_chain() {
// Use the empty tree.
let anchor = MerkleHashOrchard::empty_root(32.into()).into();

let mut builder = Builder::new(Flags::from_parts(false, true), anchor);
let mut builder =
Builder::new(Flags::from_parts(false, true), anchor, PaddingRule::DEFAULT);
assert_eq!(
builder.add_recipient(None, recipient, NoteValue::from_raw(5000), None),
Ok(())
Expand Down Expand Up @@ -83,7 +84,7 @@ fn bundle_chain() {
let anchor = root.into();
assert_eq!(anchor, merkle_path.root(cmx));

let mut builder = Builder::new(Flags::from_parts(true, true), anchor);
let mut builder = Builder::new(Flags::from_parts(true, true), anchor, PaddingRule::DEFAULT);
assert_eq!(builder.add_spend(fvk, note, merkle_path), Ok(()));
assert_eq!(
builder.add_recipient(None, recipient, NoteValue::from_raw(5000), None),
Expand Down

0 comments on commit 5ebf22d

Please sign in to comment.