mirror of https://github.com/zcash/orchard.git
Add explicit control of padding to the Builder API.
This commit is contained in:
parent
06cb76168e
commit
0a257d6f68
|
@ -6,11 +6,15 @@ and this project adheres to Rust's notion of
|
|||
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- `orchard::builder::BundleType`
|
||||
|
||||
### Changed
|
||||
- `orchard::builder::Builder::add_recipient` has been renamed to `add_output`
|
||||
in order to clarify than more than one output of a given transaction may be
|
||||
sent to the same recipient.
|
||||
- `orchard::builder::Builder::build` now takes an additional `BundleType` argument
|
||||
that specifies how actions should be padded, instead of using hardcoded padding.
|
||||
|
||||
## [0.6.0] - 2023-09-08
|
||||
### Changed
|
||||
|
|
|
@ -7,7 +7,7 @@ use criterion::{BenchmarkId, Criterion};
|
|||
use pprof::criterion::{Output, PProfProfiler};
|
||||
|
||||
use orchard::{
|
||||
builder::Builder,
|
||||
builder::{Builder, BundleType},
|
||||
bundle::Flags,
|
||||
circuit::{ProvingKey, VerifyingKey},
|
||||
keys::{FullViewingKey, Scope, SpendingKey},
|
||||
|
@ -35,7 +35,7 @@ fn criterion_benchmark(c: &mut Criterion) {
|
|||
.add_output(None, recipient, NoteValue::from_raw(10), None)
|
||||
.unwrap();
|
||||
}
|
||||
let bundle: Bundle<_, i64> = builder.build(rng).unwrap();
|
||||
let bundle: Bundle<_, i64> = builder.build(rng, &BundleType::Transactional).unwrap();
|
||||
|
||||
let instances: Vec<_> = bundle
|
||||
.actions()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
|
||||
use orchard::{
|
||||
builder::Builder,
|
||||
builder::{Builder, BundleType},
|
||||
bundle::Flags,
|
||||
circuit::ProvingKey,
|
||||
keys::{FullViewingKey, PreparedIncomingViewingKey, Scope, SpendingKey},
|
||||
|
@ -57,7 +57,7 @@ fn bench_note_decryption(c: &mut Criterion) {
|
|||
builder
|
||||
.add_output(None, recipient, NoteValue::from_raw(10), None)
|
||||
.unwrap();
|
||||
let bundle: Bundle<_, i64> = builder.build(rng).unwrap();
|
||||
let bundle: Bundle<_, i64> = builder.build(rng, &BundleType::Transactional).unwrap();
|
||||
bundle
|
||||
.create_proof(&pk, rng)
|
||||
.unwrap()
|
||||
|
|
|
@ -27,6 +27,42 @@ use crate::{
|
|||
|
||||
const MIN_ACTIONS: usize = 2;
|
||||
|
||||
/// An enumeration of rules Orchard bundle construction.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum BundleType {
|
||||
/// A transactional bundle will be padded if necessary to contain at least 2 actions,
|
||||
/// irrespective of whether any genuine actions are required.
|
||||
Transactional,
|
||||
/// A coinbase bundle is required to have no non-dummy spends. No padding is performed.
|
||||
Coinbase,
|
||||
}
|
||||
|
||||
impl BundleType {
|
||||
/// Returns the number of logical actions that builder will produce in constructing a bundle
|
||||
/// of this type, given the specified numbers of spends and outputs.
|
||||
///
|
||||
/// Returns an error if the specified number of spends and outputs is incompatible with
|
||||
/// this bundle type.
|
||||
pub fn num_actions(
|
||||
&self,
|
||||
num_spends: usize,
|
||||
num_outputs: usize,
|
||||
) -> Result<usize, &'static str> {
|
||||
let num_real_actions = core::cmp::max(num_spends, num_outputs);
|
||||
|
||||
match self {
|
||||
BundleType::Transactional => Ok(core::cmp::max(num_real_actions, MIN_ACTIONS)),
|
||||
BundleType::Coinbase => {
|
||||
if num_spends == 0 {
|
||||
Ok(num_real_actions)
|
||||
} else {
|
||||
Err("Spends not allowed in coinbase bundles")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An error type for the kinds of errors that can occur during bundle construction.
|
||||
#[derive(Debug)]
|
||||
pub enum BuildError {
|
||||
|
@ -42,6 +78,8 @@ pub enum BuildError {
|
|||
/// A signature is valid for more than one input. This should never happen if `alpha`
|
||||
/// is sampled correctly, and indicates a critical failure in randomness generation.
|
||||
DuplicateSignature,
|
||||
/// The bundle being constructed violated the construction rules for the requested bundle type.
|
||||
BundleTypeNotSatisfiable,
|
||||
}
|
||||
|
||||
impl Display for BuildError {
|
||||
|
@ -53,6 +91,9 @@ impl Display for BuildError {
|
|||
ValueSum(_) => f.write_str("Overflow occurred during value construction"),
|
||||
InvalidExternalSignature => f.write_str("External signature was invalid"),
|
||||
DuplicateSignature => f.write_str("Signature valid for more than one input"),
|
||||
BundleTypeNotSatisfiable => {
|
||||
f.write_str("Bundle structure did not conform to requested bundle type.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -388,22 +429,23 @@ impl Builder {
|
|||
pub fn build<V: TryFrom<i64>>(
|
||||
mut self,
|
||||
mut rng: impl RngCore,
|
||||
bundle_type: &BundleType,
|
||||
) -> Result<Bundle<InProgress<Unproven, Unauthorized>, V>, BuildError> {
|
||||
let num_real_spends = self.spends.len();
|
||||
let num_real_outputs = self.outputs.len();
|
||||
let num_actions = bundle_type
|
||||
.num_actions(num_real_spends, num_real_outputs)
|
||||
.map_err(|_| BuildError::BundleTypeNotSatisfiable)?;
|
||||
|
||||
// Pair up the spends and outputs, extending with dummy values as necessary.
|
||||
let pre_actions: Vec<_> = {
|
||||
let num_spends = self.spends.len();
|
||||
let num_outputs = self.outputs.len();
|
||||
let num_actions = [num_spends, num_outputs, 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.outputs.extend(
|
||||
iter::repeat_with(|| OutputInfo::dummy(&mut rng)).take(num_actions - num_outputs),
|
||||
iter::repeat_with(|| OutputInfo::dummy(&mut rng))
|
||||
.take(num_actions - num_real_outputs),
|
||||
);
|
||||
|
||||
// Shuffle the spends and outputs, so that learning the position of a
|
||||
|
@ -776,7 +818,7 @@ pub mod testing {
|
|||
Address, Note,
|
||||
};
|
||||
|
||||
use super::Builder;
|
||||
use super::{Builder, BundleType};
|
||||
|
||||
/// An intermediate type used for construction of arbitrary
|
||||
/// bundle values. This type is required because of a limitation
|
||||
|
@ -817,7 +859,7 @@ pub mod testing {
|
|||
|
||||
let pk = ProvingKey::build();
|
||||
builder
|
||||
.build(&mut self.rng)
|
||||
.build(&mut self.rng, &BundleType::Transactional)
|
||||
.unwrap()
|
||||
.create_proof(&pk, &mut self.rng)
|
||||
.unwrap()
|
||||
|
@ -898,6 +940,7 @@ mod tests {
|
|||
|
||||
use super::Builder;
|
||||
use crate::{
|
||||
builder::BundleType,
|
||||
bundle::{Authorized, Bundle, Flags},
|
||||
circuit::ProvingKey,
|
||||
constants::MERKLE_DEPTH_ORCHARD,
|
||||
|
@ -927,7 +970,7 @@ mod tests {
|
|||
assert_eq!(balance, -5000);
|
||||
|
||||
let bundle: Bundle<Authorized, i64> = builder
|
||||
.build(&mut rng)
|
||||
.build(&mut rng, &BundleType::Transactional)
|
||||
.unwrap()
|
||||
.create_proof(&pk, &mut rng)
|
||||
.unwrap()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use bridgetree::BridgeTree;
|
||||
use incrementalmerkletree::Hashable;
|
||||
use orchard::{
|
||||
builder::Builder,
|
||||
builder::{Builder, BundleType},
|
||||
bundle::{Authorized, Flags},
|
||||
circuit::{ProvingKey, VerifyingKey},
|
||||
keys::{FullViewingKey, PreparedIncomingViewingKey, Scope, SpendAuthorizingKey, SpendingKey},
|
||||
|
@ -47,7 +47,7 @@ fn bundle_chain() {
|
|||
builder.add_output(None, recipient, NoteValue::from_raw(5000), None),
|
||||
Ok(())
|
||||
);
|
||||
let unauthorized = builder.build(&mut rng).unwrap();
|
||||
let unauthorized = builder.build(&mut rng, &BundleType::Transactional).unwrap();
|
||||
let sighash = unauthorized.commitment().into();
|
||||
let proven = unauthorized.create_proof(&pk, &mut rng).unwrap();
|
||||
proven.apply_signatures(rng, sighash, &[]).unwrap()
|
||||
|
@ -89,7 +89,7 @@ fn bundle_chain() {
|
|||
builder.add_output(None, recipient, NoteValue::from_raw(5000), None),
|
||||
Ok(())
|
||||
);
|
||||
let unauthorized = builder.build(&mut rng).unwrap();
|
||||
let unauthorized = builder.build(&mut rng, &BundleType::Transactional).unwrap();
|
||||
let sighash = unauthorized.commitment().into();
|
||||
let proven = unauthorized.create_proof(&pk, &mut rng).unwrap();
|
||||
proven
|
||||
|
|
Loading…
Reference in New Issue