Merge pull request #1045 from zcash/1044-sapling-params-removal

zcash_primitives: Remove `consensus::Parameters` from `sapling` module
This commit is contained in:
str4d 2023-11-28 01:22:56 +00:00 committed by GitHub
commit 7e45a5f134
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 396 additions and 428 deletions

View File

@ -741,10 +741,12 @@ where
{ {
tx.sapling_bundle().and_then(|bundle| { tx.sapling_bundle().and_then(|bundle| {
try_sapling_note_decryption( try_sapling_note_decryption(
params,
proposal.min_target_height(),
&internal_ivk, &internal_ivk,
&bundle.shielded_outputs()[output_index], &bundle.shielded_outputs()[output_index],
consensus::sapling_zip212_enforcement(
params,
proposal.min_target_height(),
),
) )
.map(|(note, _, _)| (account, note)) .map(|(note, _, _)| (account, note))
}) })

View File

@ -56,6 +56,7 @@ pub fn decrypt_transaction<P: consensus::Parameters>(
tx: &Transaction, tx: &Transaction,
ufvks: &HashMap<AccountId, UnifiedFullViewingKey>, ufvks: &HashMap<AccountId, UnifiedFullViewingKey>,
) -> Vec<DecryptedOutput<sapling::Note>> { ) -> Vec<DecryptedOutput<sapling::Note>> {
let zip212_enforcement = consensus::sapling_zip212_enforcement(params, height);
tx.sapling_bundle() tx.sapling_bundle()
.iter() .iter()
.flat_map(|bundle| { .flat_map(|bundle| {
@ -76,19 +77,18 @@ pub fn decrypt_transaction<P: consensus::Parameters>(
.iter() .iter()
.enumerate() .enumerate()
.flat_map(move |(index, output)| { .flat_map(move |(index, output)| {
try_sapling_note_decryption(params, height, &ivk_external, output) try_sapling_note_decryption(&ivk_external, output, zip212_enforcement)
.map(|ret| (ret, TransferType::Incoming)) .map(|ret| (ret, TransferType::Incoming))
.or_else(|| { .or_else(|| {
try_sapling_note_decryption( try_sapling_note_decryption(
params,
height,
&ivk_internal, &ivk_internal,
output, output,
zip212_enforcement,
) )
.map(|ret| (ret, TransferType::WalletInternal)) .map(|ret| (ret, TransferType::WalletInternal))
}) })
.or_else(|| { .or_else(|| {
try_sapling_output_recovery(params, height, &ovk, output) try_sapling_output_recovery(&ovk, output, zip212_enforcement)
.map(|ret| (ret, TransferType::Outgoing)) .map(|ret| (ret, TransferType::Outgoing))
}) })
.into_iter() .into_iter()

View File

@ -267,22 +267,23 @@ pub fn scan_block<P: consensus::Parameters + Send + 'static, K: ScanningKey>(
) )
} }
type TaggedBatch<P, S> = Batch<(AccountId, S), SaplingDomain<P>, CompactOutputDescription>; type TaggedBatch<S> = Batch<(AccountId, S), SaplingDomain, CompactOutputDescription>;
type TaggedBatchRunner<P, S, T> = type TaggedBatchRunner<S, T> =
BatchRunner<(AccountId, S), SaplingDomain<P>, CompactOutputDescription, T>; BatchRunner<(AccountId, S), SaplingDomain, CompactOutputDescription, T>;
#[tracing::instrument(skip_all, fields(height = block.height))] #[tracing::instrument(skip_all, fields(height = block.height))]
pub(crate) fn add_block_to_runner<P, S, T>( pub(crate) fn add_block_to_runner<P, S, T>(
params: &P, params: &P,
block: CompactBlock, block: CompactBlock,
batch_runner: &mut TaggedBatchRunner<P, S, T>, batch_runner: &mut TaggedBatchRunner<S, T>,
) where ) where
P: consensus::Parameters + Send + 'static, P: consensus::Parameters + Send + 'static,
S: Clone + Send + 'static, S: Clone + Send + 'static,
T: Tasks<TaggedBatch<P, S>>, T: Tasks<TaggedBatch<S>>,
{ {
let block_hash = block.hash(); let block_hash = block.hash();
let block_height = block.height(); let block_height = block.height();
let zip212_enforcement = consensus::sapling_zip212_enforcement(params, block_height);
for tx in block.vtx.into_iter() { for tx in block.vtx.into_iter() {
let txid = tx.txid(); let txid = tx.txid();
@ -298,7 +299,7 @@ pub(crate) fn add_block_to_runner<P, S, T>(
batch_runner.add_outputs( batch_runner.add_outputs(
block_hash, block_hash,
txid, txid,
|| SaplingDomain::for_height(params.clone(), block_height), || SaplingDomain::new(zip212_enforcement),
&outputs, &outputs,
) )
} }
@ -330,14 +331,14 @@ fn check_hash_continuity(
pub(crate) fn scan_block_with_runner< pub(crate) fn scan_block_with_runner<
P: consensus::Parameters + Send + 'static, P: consensus::Parameters + Send + 'static,
K: ScanningKey, K: ScanningKey,
T: Tasks<TaggedBatch<P, K::Scope>> + Sync, T: Tasks<TaggedBatch<K::Scope>> + Sync,
>( >(
params: &P, params: &P,
block: CompactBlock, block: CompactBlock,
vks: &[(&AccountId, K)], vks: &[(&AccountId, K)],
nullifiers: &[(AccountId, sapling::Nullifier)], nullifiers: &[(AccountId, sapling::Nullifier)],
prior_block_metadata: Option<&BlockMetadata>, prior_block_metadata: Option<&BlockMetadata>,
mut batch_runner: Option<&mut TaggedBatchRunner<P, K::Scope, T>>, mut batch_runner: Option<&mut TaggedBatchRunner<K::Scope, T>>,
) -> Result<ScannedBlock<K::Nf>, ScanError> { ) -> Result<ScannedBlock<K::Nf>, ScanError> {
if let Some(scan_error) = check_hash_continuity(&block, prior_block_metadata) { if let Some(scan_error) = check_hash_continuity(&block, prior_block_metadata) {
return Err(scan_error); return Err(scan_error);
@ -345,6 +346,7 @@ pub(crate) fn scan_block_with_runner<
let cur_height = block.height(); let cur_height = block.height();
let cur_hash = block.hash(); let cur_hash = block.hash();
let zip212_enforcement = consensus::sapling_zip212_enforcement(params, cur_height);
let initial_sapling_tree_size = prior_block_metadata.and_then(|m| m.sapling_tree_size()); let initial_sapling_tree_size = prior_block_metadata.and_then(|m| m.sapling_tree_size());
let mut sapling_commitment_tree_size = initial_sapling_tree_size.map_or_else( let mut sapling_commitment_tree_size = initial_sapling_tree_size.map_or_else(
@ -498,7 +500,7 @@ pub(crate) fn scan_block_with_runner<
.into_iter() .into_iter()
.map(|output| { .map(|output| {
( (
SaplingDomain::for_height(params.clone(), cur_height), SaplingDomain::new(zip212_enforcement),
CompactOutputDescription::try_from(output) CompactOutputDescription::try_from(output)
.expect("Invalid output found in compact block decoding."), .expect("Invalid output found in compact block decoding."),
) )
@ -655,7 +657,7 @@ mod tests {
use zcash_note_encryption::Domain; use zcash_note_encryption::Domain;
use zcash_primitives::{ use zcash_primitives::{
block::BlockHash, block::BlockHash,
consensus::{BlockHeight, Network}, consensus::{sapling_zip212_enforcement, BlockHeight, Network},
memo::MemoBytes, memo::MemoBytes,
sapling::{ sapling::{
self, self,
@ -726,22 +728,21 @@ mod tests {
tx_after: bool, tx_after: bool,
initial_tree_sizes: Option<(u32, u32)>, initial_tree_sizes: Option<(u32, u32)>,
) -> CompactBlock { ) -> CompactBlock {
let zip212_enforcement = sapling_zip212_enforcement(&Network::TestNetwork, height);
let to = dfvk.default_address().1; let to = dfvk.default_address().1;
// Create a fake Note for the account // Create a fake Note for the account
let mut rng = OsRng; let mut rng = OsRng;
let rseed = generate_random_rseed(&Network::TestNetwork, height, &mut rng); let rseed = generate_random_rseed(zip212_enforcement, &mut rng);
let note = sapling::Note::from_parts(to, NoteValue::from(value), rseed); let note = sapling::Note::from_parts(to, NoteValue::from(value), rseed);
let encryptor = sapling_note_encryption::<_, Network>( let encryptor = sapling_note_encryption(
Some(dfvk.fvk().ovk), Some(dfvk.fvk().ovk),
note.clone(), note.clone(),
MemoBytes::empty(), MemoBytes::empty(),
&mut rng, &mut rng,
); );
let cmu = note.cmu().to_bytes().to_vec(); let cmu = note.cmu().to_bytes().to_vec();
let ephemeral_key = SaplingDomain::<Network>::epk_bytes(encryptor.epk()) let ephemeral_key = SaplingDomain::epk_bytes(encryptor.epk()).0.to_vec();
.0
.to_vec();
let enc_ciphertext = encryptor.encrypt_note_plaintext(); let enc_ciphertext = encryptor.encrypt_note_plaintext();
// Create a fake CompactBlock containing the note // Create a fake CompactBlock containing the note

View File

@ -770,18 +770,19 @@ pub(crate) fn fake_compact_block<P: consensus::Parameters>(
// Create a fake Note for the account // Create a fake Note for the account
let mut rng = OsRng; let mut rng = OsRng;
let rseed = generate_random_rseed(params, height, &mut rng); let rseed = generate_random_rseed(
consensus::sapling_zip212_enforcement(params, height),
&mut rng,
);
let note = Note::from_parts(to, NoteValue::from(value), rseed); let note = Note::from_parts(to, NoteValue::from(value), rseed);
let encryptor = sapling_note_encryption::<_, Network>( let encryptor = sapling_note_encryption(
Some(dfvk.fvk().ovk), Some(dfvk.fvk().ovk),
note.clone(), note.clone(),
MemoBytes::empty(), MemoBytes::empty(),
&mut rng, &mut rng,
); );
let cmu = note.cmu().to_bytes().to_vec(); let cmu = note.cmu().to_bytes().to_vec();
let ephemeral_key = SaplingDomain::<Network>::epk_bytes(encryptor.epk()) let ephemeral_key = SaplingDomain::epk_bytes(encryptor.epk()).0.to_vec();
.0
.to_vec();
let enc_ciphertext = encryptor.encrypt_note_plaintext(); let enc_ciphertext = encryptor.encrypt_note_plaintext();
// Create a fake CompactBlock containing the note // Create a fake CompactBlock containing the note
@ -866,8 +867,9 @@ pub(crate) fn fake_compact_block_spending<P: consensus::Parameters>(
value: NonNegativeAmount, value: NonNegativeAmount,
initial_sapling_tree_size: u32, initial_sapling_tree_size: u32,
) -> CompactBlock { ) -> CompactBlock {
let zip212_enforcement = consensus::sapling_zip212_enforcement(params, height);
let mut rng = OsRng; let mut rng = OsRng;
let rseed = generate_random_rseed(params, height, &mut rng); let rseed = generate_random_rseed(zip212_enforcement, &mut rng);
// Create a fake CompactBlock containing the note // Create a fake CompactBlock containing the note
let cspend = CompactSaplingSpend { nf: nf.to_vec() }; let cspend = CompactSaplingSpend { nf: nf.to_vec() };
@ -880,16 +882,14 @@ pub(crate) fn fake_compact_block_spending<P: consensus::Parameters>(
// Create a fake Note for the payment // Create a fake Note for the payment
ctx.outputs.push({ ctx.outputs.push({
let note = Note::from_parts(to, NoteValue::from(value), rseed); let note = Note::from_parts(to, NoteValue::from(value), rseed);
let encryptor = sapling_note_encryption::<_, Network>( let encryptor = sapling_note_encryption(
Some(dfvk.fvk().ovk), Some(dfvk.fvk().ovk),
note.clone(), note.clone(),
MemoBytes::empty(), MemoBytes::empty(),
&mut rng, &mut rng,
); );
let cmu = note.cmu().to_bytes().to_vec(); let cmu = note.cmu().to_bytes().to_vec();
let ephemeral_key = SaplingDomain::<Network>::epk_bytes(encryptor.epk()) let ephemeral_key = SaplingDomain::epk_bytes(encryptor.epk()).0.to_vec();
.0
.to_vec();
let enc_ciphertext = encryptor.encrypt_note_plaintext(); let enc_ciphertext = encryptor.encrypt_note_plaintext();
CompactSaplingOutput { CompactSaplingOutput {
@ -902,22 +902,20 @@ pub(crate) fn fake_compact_block_spending<P: consensus::Parameters>(
// Create a fake Note for the change // Create a fake Note for the change
ctx.outputs.push({ ctx.outputs.push({
let change_addr = dfvk.default_address().1; let change_addr = dfvk.default_address().1;
let rseed = generate_random_rseed(params, height, &mut rng); let rseed = generate_random_rseed(zip212_enforcement, &mut rng);
let note = Note::from_parts( let note = Note::from_parts(
change_addr, change_addr,
NoteValue::from((in_value - value).unwrap()), NoteValue::from((in_value - value).unwrap()),
rseed, rseed,
); );
let encryptor = sapling_note_encryption::<_, Network>( let encryptor = sapling_note_encryption(
Some(dfvk.fvk().ovk), Some(dfvk.fvk().ovk),
note.clone(), note.clone(),
MemoBytes::empty(), MemoBytes::empty(),
&mut rng, &mut rng,
); );
let cmu = note.cmu().to_bytes().to_vec(); let cmu = note.cmu().to_bytes().to_vec();
let ephemeral_key = SaplingDomain::<Network>::epk_bytes(encryptor.epk()) let ephemeral_key = SaplingDomain::epk_bytes(encryptor.epk()).0.to_vec();
.0
.to_vec();
let enc_ciphertext = encryptor.encrypt_note_plaintext(); let enc_ciphertext = encryptor.encrypt_note_plaintext();
CompactSaplingOutput { CompactSaplingOutput {

View File

@ -423,7 +423,7 @@ pub(crate) mod tests {
use zcash_primitives::{ use zcash_primitives::{
block::BlockHash, block::BlockHash,
consensus::BranchId, consensus::{sapling_zip212_enforcement, BranchId},
legacy::TransparentAddress, legacy::TransparentAddress,
memo::{Memo, MemoBytes}, memo::{Memo, MemoBytes},
sapling::{ sapling::{
@ -1033,10 +1033,9 @@ pub(crate) mod tests {
for output in tx.sapling_bundle().unwrap().shielded_outputs() { for output in tx.sapling_bundle().unwrap().shielded_outputs() {
// Find the output that decrypts with the external OVK // Find the output that decrypts with the external OVK
let result = try_sapling_output_recovery( let result = try_sapling_output_recovery(
&st.network(),
h1,
&dfvk.to_ovk(Scope::External), &dfvk.to_ovk(Scope::External),
output, output,
sapling_zip212_enforcement(&st.network(), h1),
); );
if result.is_some() { if result.is_some() {

View File

@ -8,6 +8,7 @@ and this library adheres to Rust's notion of
## [Unreleased] ## [Unreleased]
### Added ### Added
- Dependency on `bellman 0.14`. - Dependency on `bellman 0.14`.
- `zcash_primitives::consensus::sapling_zip212_enforcement`
- `zcash_primitives::sapling`: - `zcash_primitives::sapling`:
- `BatchValidator` (moved from `zcash_proofs::sapling`). - `BatchValidator` (moved from `zcash_proofs::sapling`).
- `SaplingVerificationContext` (moved from `zcash_proofs::sapling`). - `SaplingVerificationContext` (moved from `zcash_proofs::sapling`).
@ -46,6 +47,8 @@ and this library adheres to Rust's notion of
- `constants` module. - `constants` module.
- `note_encryption::CompactOutputDescription` (moved from - `note_encryption::CompactOutputDescription` (moved from
`zcash_primitives::transaction::components::sapling`). `zcash_primitives::transaction::components::sapling`).
- `note_encryption::SaplingDomain::new`
- `note_encryption::Zip212Enforcement`
- `prover::{SpendProver, OutputProver}` - `prover::{SpendProver, OutputProver}`
- `value`: - `value`:
- `ValueCommitTrapdoor::from_bytes` - `ValueCommitTrapdoor::from_bytes`
@ -95,12 +98,16 @@ and this library adheres to Rust's notion of
newtypes. newtypes.
- `address::PaymentAddress::create_note` now takes its `value` argument as a - `address::PaymentAddress::create_note` now takes its `value` argument as a
`NoteValue` instead of as a bare `u64`. `NoteValue` instead of as a bare `u64`.
- `builder::SaplingBuilder` no longer has a `P: consensus::Parameters` type
parameter.
- `builder::SaplingBuilder::new` now takes a `Zip212Enforcement` argument
instead of a `P: consensus::Parameters` argument and a target height.
- `builder::SaplingBuilder::add_spend` now takes `extsk` by reference. - `builder::SaplingBuilder::add_spend` now takes `extsk` by reference.
- `builder::SaplingBuilder::build` no longer takes a prover, proving context, - `builder::SaplingBuilder::build` no longer takes a prover, proving context,
or progress notifier. Instead, it has `SpendProver, OutputProver` generic progress notifier, or target height. Instead, it has `SpendProver, OutputProver`
parameters and returns `(UnauthorizedBundle, SaplingMetadata)`. The caller generic parameters and returns `(UnauthorizedBundle, SaplingMetadata)`. The
can then use `Bundle::<InProgress<Unproven, _>>::create_proofs` to create caller can then use `Bundle::<InProgress<Unproven, _>>::create_proofs` to
spend and output proofs for the bundle. create spend and output proofs for the bundle.
- `builder::Error` has new error variants: - `builder::Error` has new error variants:
- `Error::DuplicateSignature` - `Error::DuplicateSignature`
- `Error::InvalidExternalSignature` - `Error::InvalidExternalSignature`
@ -108,6 +115,17 @@ and this library adheres to Rust's notion of
- `bundle::MapAuth` trait methods now take `&mut self` instead of `&self`. - `bundle::MapAuth` trait methods now take `&mut self` instead of `&self`.
- `circuit::ValueCommitmentOpening::value` is now represented as a `NoteValue` - `circuit::ValueCommitmentOpening::value` is now represented as a `NoteValue`
instead of as a bare `u64`. instead of as a bare `u64`.
- `note_encryption`:
- `SaplingDomain` no longer has a `P: consensus::Parameters` type parameter.
- The following methods now take a `Zip212Enforcement` argument instead of a
`P: consensus::Parameters` argument:
- `plaintext_version_is_valid`
- `try_sapling_note_decryption`
- `try_sapling_compact_note_decryption`
- `try_sapling_output_recovery_with_ock`
- `try_sapling_output_recovery`
- `util::generate_random_rseed` now takes a `Zip212Enforcement` argument
instead of a `P: consensus::Parameters` argument and a height.
- `zcash_primitives::transaction`: - `zcash_primitives::transaction`:
- `builder::Builder::{build, build_zfuture}` now take - `builder::Builder::{build, build_zfuture}` now take
`&impl SpendProver, &impl OutputProver` instead of `&impl TxProver`. `&impl SpendProver, &impl OutputProver` instead of `&impl TxProver`.
@ -135,13 +153,16 @@ and this library adheres to Rust's notion of
### Removed ### Removed
- `zcash_primitives::constants`: - `zcash_primitives::constants`:
- All `const` values (moved to `zcash_primitives::sapling::constants`). - All `const` values (moved to `zcash_primitives::sapling::constants`).
- `zcash_primitives::sapling::bundle`: - `zcash_primitives::sapling`:
- `SpendDescription::{read, read_nullifier, read_rk, read_spend_auth_sig}` - `bundle`:
- `SpendDescription::{write_v4, write_v5_without_witness_data}` - `SpendDescription::{read, read_nullifier, read_rk, read_spend_auth_sig}`
- `SpendDescriptionV5::read` - `SpendDescription::{write_v4, write_v5_without_witness_data}`
- `OutputDescription::read` - `SpendDescriptionV5::read`
- `OutputDescription::{write_v4, write_v5_without_proof}` - `OutputDescription::read`
- `OutputDescriptionV5::read` - `OutputDescription::{write_v4, write_v5_without_proof}`
- `OutputDescriptionV5::read`
- `note_encryption::SaplingDomain::for_height` (use `SaplingDomain::new`
instead).
- `zcash_primitives::transaction::components::sapling`: - `zcash_primitives::transaction::components::sapling`:
- The following types were removed from this module (moved into - The following types were removed from this module (moved into
`zcash_primitives::sapling::bundle`): `zcash_primitives::sapling::bundle`):

View File

@ -5,7 +5,7 @@ use ff::Field;
use rand_core::OsRng; use rand_core::OsRng;
use zcash_note_encryption::batch; use zcash_note_encryption::batch;
use zcash_primitives::{ use zcash_primitives::{
consensus::{NetworkUpgrade::Canopy, Parameters, TEST_NETWORK}, consensus::{sapling_zip212_enforcement, NetworkUpgrade::Canopy, Parameters, TEST_NETWORK},
memo::MemoBytes, memo::MemoBytes,
sapling::{ sapling::{
builder::SaplingBuilder, builder::SaplingBuilder,
@ -25,6 +25,7 @@ use pprof::criterion::{Output, PProfProfiler};
fn bench_note_decryption(c: &mut Criterion) { fn bench_note_decryption(c: &mut Criterion) {
let mut rng = OsRng; let mut rng = OsRng;
let height = TEST_NETWORK.activation_height(Canopy).unwrap(); let height = TEST_NETWORK.activation_height(Canopy).unwrap();
let zip212_enforcement = sapling_zip212_enforcement(&TEST_NETWORK, height);
let valid_ivk = SaplingIvk(jubjub::Fr::random(&mut rng)); let valid_ivk = SaplingIvk(jubjub::Fr::random(&mut rng));
let invalid_ivk = SaplingIvk(jubjub::Fr::random(&mut rng)); let invalid_ivk = SaplingIvk(jubjub::Fr::random(&mut rng));
@ -34,7 +35,7 @@ fn bench_note_decryption(c: &mut Criterion) {
let diversifier = Diversifier([0; 11]); let diversifier = Diversifier([0; 11]);
let pa = valid_ivk.to_payment_address(diversifier).unwrap(); let pa = valid_ivk.to_payment_address(diversifier).unwrap();
let mut builder = SaplingBuilder::new(TEST_NETWORK, height); let mut builder = SaplingBuilder::new(zip212_enforcement);
builder builder
.add_output( .add_output(
&mut rng, &mut rng,
@ -45,7 +46,7 @@ fn bench_note_decryption(c: &mut Criterion) {
) )
.unwrap(); .unwrap();
let (bundle, _) = builder let (bundle, _) = builder
.build::<MockSpendProver, MockOutputProver, _>(&mut rng, height) .build::<MockSpendProver, MockOutputProver, _>(&mut rng)
.unwrap() .unwrap()
.unwrap(); .unwrap();
bundle.shielded_outputs()[0].clone() bundle.shielded_outputs()[0].clone()
@ -59,27 +60,25 @@ fn bench_note_decryption(c: &mut Criterion) {
group.throughput(Throughput::Elements(1)); group.throughput(Throughput::Elements(1));
group.bench_function("valid", |b| { group.bench_function("valid", |b| {
b.iter(|| { b.iter(|| try_sapling_note_decryption(&valid_ivk, &output, zip212_enforcement).unwrap())
try_sapling_note_decryption(&TEST_NETWORK, height, &valid_ivk, &output).unwrap()
})
}); });
group.bench_function("invalid", |b| { group.bench_function("invalid", |b| {
b.iter(|| try_sapling_note_decryption(&TEST_NETWORK, height, &invalid_ivk, &output)) b.iter(|| try_sapling_note_decryption(&invalid_ivk, &output, zip212_enforcement))
}); });
let compact = CompactOutputDescription::from(output.clone()); let compact = CompactOutputDescription::from(output.clone());
group.bench_function("compact-valid", |b| { group.bench_function("compact-valid", |b| {
b.iter(|| { b.iter(|| {
try_sapling_compact_note_decryption(&TEST_NETWORK, height, &valid_ivk, &compact) try_sapling_compact_note_decryption(&valid_ivk, &compact, zip212_enforcement)
.unwrap() .unwrap()
}) })
}); });
group.bench_function("compact-invalid", |b| { group.bench_function("compact-invalid", |b| {
b.iter(|| { b.iter(|| {
try_sapling_compact_note_decryption(&TEST_NETWORK, height, &invalid_ivk, &compact) try_sapling_compact_note_decryption(&invalid_ivk, &compact, zip212_enforcement)
}) })
}); });
} }
@ -93,7 +92,7 @@ fn bench_note_decryption(c: &mut Criterion) {
let outputs: Vec<_> = iter::repeat(output.clone()) let outputs: Vec<_> = iter::repeat(output.clone())
.take(noutputs) .take(noutputs)
.map(|output| (SaplingDomain::for_height(TEST_NETWORK, height), output)) .map(|output| (SaplingDomain::new(zip212_enforcement), output))
.collect(); .collect();
group.bench_function( group.bench_function(

View File

@ -7,7 +7,7 @@ use std::fmt;
use std::ops::{Add, Bound, RangeBounds, Sub}; use std::ops::{Add, Bound, RangeBounds, Sub};
use zcash_address; use zcash_address;
use crate::constants; use crate::{constants, sapling::note_encryption::Zip212Enforcement};
/// A wrapper type representing blockchain heights. Safe conversion from /// A wrapper type representing blockchain heights. Safe conversion from
/// various integer types, as well as addition and subtraction, are provided. /// various integer types, as well as addition and subtraction, are provided.
@ -599,6 +599,25 @@ impl BranchId {
} }
} }
/// Returns the enforcement policy for ZIP 212 at the given height.
pub fn sapling_zip212_enforcement(
params: &impl Parameters,
height: BlockHeight,
) -> Zip212Enforcement {
if params.is_nu_active(NetworkUpgrade::Canopy, height) {
let grace_period_end_height =
params.activation_height(NetworkUpgrade::Canopy).unwrap() + ZIP212_GRACE_PERIOD;
if height < grace_period_end_height {
Zip212Enforcement::GracePeriod
} else {
Zip212Enforcement::On
}
} else {
Zip212Enforcement::Off
}
}
#[cfg(any(test, feature = "test-dependencies"))] #[cfg(any(test, feature = "test-dependencies"))]
pub mod testing { pub mod testing {
use proptest::sample::select; use proptest::sample::select;

View File

@ -8,7 +8,6 @@ use rand::{seq::SliceRandom, RngCore};
use rand_core::CryptoRng; use rand_core::CryptoRng;
use crate::{ use crate::{
consensus::{self, BlockHeight},
keys::OutgoingViewingKey, keys::OutgoingViewingKey,
memo::MemoBytes, memo::MemoBytes,
sapling::{ sapling::{
@ -18,7 +17,7 @@ use crate::{
SpendDescription, SpendDescription,
}, },
constants::{SPENDING_KEY_GENERATOR, VALUE_COMMITMENT_RANDOMNESS_GENERATOR}, constants::{SPENDING_KEY_GENERATOR, VALUE_COMMITMENT_RANDOMNESS_GENERATOR},
note_encryption::sapling_note_encryption, note_encryption::{sapling_note_encryption, Zip212Enforcement},
prover::{OutputProver, SpendProver}, prover::{OutputProver, SpendProver},
redjubjub::{PrivateKey, PublicKey, Signature}, redjubjub::{PrivateKey, PublicKey, Signature},
spend_sig_internal, spend_sig_internal,
@ -174,11 +173,7 @@ struct SaplingOutputInfo {
} }
impl SaplingOutputInfo { impl SaplingOutputInfo {
fn dummy<P: consensus::Parameters, R: RngCore>( fn dummy<R: RngCore>(mut rng: &mut R, zip212_enforcement: Zip212Enforcement) -> Self {
params: &P,
mut rng: &mut R,
target_height: BlockHeight,
) -> Self {
// This is a dummy output // This is a dummy output
let dummy_to = { let dummy_to = {
let mut diversifier = Diversifier([0; 11]); let mut diversifier = Diversifier([0; 11]);
@ -192,26 +187,24 @@ impl SaplingOutputInfo {
}; };
Self::new_internal( Self::new_internal(
params,
rng, rng,
target_height,
None, None,
dummy_to, dummy_to,
NoteValue::from_raw(0), NoteValue::from_raw(0),
MemoBytes::empty(), MemoBytes::empty(),
zip212_enforcement,
) )
} }
fn new_internal<P: consensus::Parameters, R: RngCore>( fn new_internal<R: RngCore>(
params: &P,
rng: &mut R, rng: &mut R,
target_height: BlockHeight,
ovk: Option<OutgoingViewingKey>, ovk: Option<OutgoingViewingKey>,
to: PaymentAddress, to: PaymentAddress,
value: NoteValue, value: NoteValue,
memo: MemoBytes, memo: MemoBytes,
zip212_enforcement: Zip212Enforcement,
) -> Self { ) -> Self {
let rseed = generate_random_rseed_internal(params, target_height, rng); let rseed = generate_random_rseed_internal(zip212_enforcement, rng);
let note = Note::from_parts(to, value, rseed); let note = Note::from_parts(to, value, rseed);
@ -223,12 +216,11 @@ impl SaplingOutputInfo {
} }
} }
fn build<P: consensus::Parameters, Pr: OutputProver, R: RngCore>( fn build<Pr: OutputProver, R: RngCore>(
self, self,
rng: &mut R, rng: &mut R,
) -> OutputDescription<sapling::circuit::Output> { ) -> OutputDescription<sapling::circuit::Output> {
let encryptor = let encryptor = sapling_note_encryption::<R>(self.ovk, self.note.clone(), self.memo, rng);
sapling_note_encryption::<R, P>(self.ovk, self.note.clone(), self.memo, rng);
// Construct the value commitment. // Construct the value commitment.
let cv = ValueCommitment::derive(self.note.value(), self.rcv.clone()); let cv = ValueCommitment::derive(self.note.value(), self.rcv.clone());
@ -305,24 +297,22 @@ impl SaplingMetadata {
} }
} }
pub struct SaplingBuilder<P> { pub struct SaplingBuilder {
params: P,
anchor: Option<bls12_381::Scalar>, anchor: Option<bls12_381::Scalar>,
target_height: BlockHeight,
value_balance: ValueSum, value_balance: ValueSum,
spends: Vec<SpendDescriptionInfo>, spends: Vec<SpendDescriptionInfo>,
outputs: Vec<SaplingOutputInfo>, outputs: Vec<SaplingOutputInfo>,
zip212_enforcement: Zip212Enforcement,
} }
impl<P> SaplingBuilder<P> { impl SaplingBuilder {
pub fn new(params: P, target_height: BlockHeight) -> Self { pub fn new(zip212_enforcement: Zip212Enforcement) -> Self {
SaplingBuilder { SaplingBuilder {
params,
anchor: None, anchor: None,
target_height,
value_balance: ValueSum::zero(), value_balance: ValueSum::zero(),
spends: vec![], spends: vec![],
outputs: vec![], outputs: vec![],
zip212_enforcement,
} }
} }
@ -366,9 +356,7 @@ impl<P> SaplingBuilder<P> {
self.try_value_balance() self.try_value_balance()
.expect("we check this when mutating self.value_balance") .expect("we check this when mutating self.value_balance")
} }
}
impl<P: consensus::Parameters> SaplingBuilder<P> {
/// Adds a Sapling note to be spent in this transaction. /// Adds a Sapling note to be spent in this transaction.
/// ///
/// Returns an error if the given Merkle path does not have the same anchor as the /// Returns an error if the given Merkle path does not have the same anchor as the
@ -414,13 +402,12 @@ impl<P: consensus::Parameters> SaplingBuilder<P> {
memo: MemoBytes, memo: MemoBytes,
) -> Result<(), Error> { ) -> Result<(), Error> {
let output = SaplingOutputInfo::new_internal( let output = SaplingOutputInfo::new_internal(
&self.params,
&mut rng, &mut rng,
self.target_height,
ovk, ovk,
to, to,
value, value,
memo, memo,
self.zip212_enforcement,
); );
self.value_balance = (self.value_balance - value).ok_or(Error::InvalidAddress)?; self.value_balance = (self.value_balance - value).ok_or(Error::InvalidAddress)?;
@ -434,7 +421,6 @@ impl<P: consensus::Parameters> SaplingBuilder<P> {
pub fn build<SP: SpendProver, OP: OutputProver, R: RngCore>( pub fn build<SP: SpendProver, OP: OutputProver, R: RngCore>(
self, self,
mut rng: R, mut rng: R,
target_height: BlockHeight,
) -> Result<Option<(UnauthorizedBundle, SaplingMetadata)>, Error> { ) -> Result<Option<(UnauthorizedBundle, SaplingMetadata)>, Error> {
let value_balance = self.try_value_balance()?; let value_balance = self.try_value_balance()?;
@ -486,7 +472,7 @@ impl<P: consensus::Parameters> SaplingBuilder<P> {
output output
} else { } else {
// This is a dummy output // This is a dummy output
SaplingOutputInfo::dummy(&self.params, &mut rng, target_height) SaplingOutputInfo::dummy(&mut rng, self.zip212_enforcement)
} }
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -505,7 +491,7 @@ impl<P: consensus::Parameters> SaplingBuilder<P> {
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Vec<_>, _>>()?;
let shielded_outputs = output_infos let shielded_outputs = output_infos
.into_iter() .into_iter()
.map(|a| a.build::<P, OP, _>(&mut rng)) .map(|a| a.build::<OP, _>(&mut rng))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
// Verify that bsk and bvk are consistent. // Verify that bsk and bvk are consistent.
@ -881,12 +867,9 @@ pub mod testing {
use rand::{rngs::StdRng, SeedableRng}; use rand::{rngs::StdRng, SeedableRng};
use crate::{ use crate::{
consensus::{
testing::{arb_branch_id, arb_height},
TEST_NETWORK,
},
sapling::{ sapling::{
bundle::{Authorized, Bundle}, bundle::{Authorized, Bundle},
note_encryption::Zip212Enforcement,
prover::mock::{MockOutputProver, MockSpendProver}, prover::mock::{MockOutputProver, MockSpendProver},
redjubjub::PrivateKey, redjubjub::PrivateKey,
testing::{arb_node, arb_note}, testing::{arb_node, arb_note},
@ -903,7 +886,7 @@ pub mod testing {
use super::SaplingBuilder; use super::SaplingBuilder;
prop_compose! { prop_compose! {
fn arb_bundle()(n_notes in 1..30usize)( fn arb_bundle(zip212_enforcement: Zip212Enforcement)(n_notes in 1..30usize)(
extsk in arb_extended_spending_key(), extsk in arb_extended_spending_key(),
spendable_notes in vec( spendable_notes in vec(
arb_positive_note_value(MAX_MONEY as u64 / 10000).prop_flat_map(arb_note), arb_positive_note_value(MAX_MONEY as u64 / 10000).prop_flat_map(arb_note),
@ -916,11 +899,10 @@ pub mod testing {
n_notes n_notes
), ),
diversifiers in vec(prop::array::uniform11(any::<u8>()).prop_map(Diversifier), n_notes), diversifiers in vec(prop::array::uniform11(any::<u8>()).prop_map(Diversifier), n_notes),
target_height in arb_branch_id().prop_flat_map(|b| arb_height(b, &TEST_NETWORK)),
rng_seed in prop::array::uniform32(any::<u8>()), rng_seed in prop::array::uniform32(any::<u8>()),
fake_sighash_bytes in prop::array::uniform32(any::<u8>()), fake_sighash_bytes in prop::array::uniform32(any::<u8>()),
) -> Bundle<Authorized> { ) -> Bundle<Authorized> {
let mut builder = SaplingBuilder::new(TEST_NETWORK, target_height.unwrap()); let mut builder = SaplingBuilder::new(zip212_enforcement);
let mut rng = StdRng::from_seed(rng_seed); let mut rng = StdRng::from_seed(rng_seed);
for ((note, path), diversifier) in spendable_notes.into_iter().zip(commitment_trees.into_iter()).zip(diversifiers.into_iter()) { for ((note, path), diversifier) in spendable_notes.into_iter().zip(commitment_trees.into_iter()).zip(diversifiers.into_iter()) {
@ -933,10 +915,10 @@ pub mod testing {
).unwrap(); ).unwrap();
} }
let (bundle, _) = builder.build::<MockSpendProver, MockOutputProver, _>( let (bundle, _) = builder
&mut rng, .build::<MockSpendProver, MockOutputProver, _>(&mut rng)
target_height.unwrap(), .unwrap()
).unwrap().unwrap(); .unwrap();
let bundle = bundle.create_proofs( let bundle = bundle.create_proofs(
&MockSpendProver, &MockSpendProver,

View File

@ -7,7 +7,6 @@ use zcash_note_encryption::{
}; };
use crate::{ use crate::{
consensus,
sapling::{ sapling::{
note::ExtractedNoteCommitment, note::ExtractedNoteCommitment,
note_encryption::{CompactOutputDescription, SaplingDomain}, note_encryption::{CompactOutputDescription, SaplingDomain},
@ -533,9 +532,7 @@ impl<Proof: DynamicUsage> DynamicUsage for OutputDescription<Proof> {
} }
} }
impl<P: consensus::Parameters, A> ShieldedOutput<SaplingDomain<P>, ENC_CIPHERTEXT_SIZE> impl<A> ShieldedOutput<SaplingDomain, ENC_CIPHERTEXT_SIZE> for OutputDescription<A> {
for OutputDescription<A>
{
fn ephemeral_key(&self) -> EphemeralKeyBytes { fn ephemeral_key(&self) -> EphemeralKeyBytes {
self.ephemeral_key.clone() self.ephemeral_key.clone()
} }

File diff suppressed because it is too large Load Diff

View File

@ -2,9 +2,7 @@ use blake2b_simd::Params;
use ff::Field; use ff::Field;
use rand_core::{CryptoRng, RngCore}; use rand_core::{CryptoRng, RngCore};
use crate::consensus::{self, BlockHeight, NetworkUpgrade}; use super::{note_encryption::Zip212Enforcement, Rseed};
use super::Rseed;
pub fn hash_to_scalar(persona: &[u8], a: &[u8], b: &[u8]) -> jubjub::Fr { pub fn hash_to_scalar(persona: &[u8], a: &[u8], b: &[u8]) -> jubjub::Fr {
let mut hasher = Params::new().hash_length(64).personal(persona).to_state(); let mut hasher = Params::new().hash_length(64).personal(persona).to_state();
@ -14,24 +12,23 @@ pub fn hash_to_scalar(persona: &[u8], a: &[u8], b: &[u8]) -> jubjub::Fr {
jubjub::Fr::from_bytes_wide(ret.as_array()) jubjub::Fr::from_bytes_wide(ret.as_array())
} }
pub fn generate_random_rseed<P: consensus::Parameters, R: RngCore + CryptoRng>( pub fn generate_random_rseed<R: RngCore + CryptoRng>(
params: &P, zip212_enforcement: Zip212Enforcement,
height: BlockHeight,
rng: &mut R, rng: &mut R,
) -> Rseed { ) -> Rseed {
generate_random_rseed_internal(params, height, rng) generate_random_rseed_internal(zip212_enforcement, rng)
} }
pub(crate) fn generate_random_rseed_internal<P: consensus::Parameters, R: RngCore>( pub(crate) fn generate_random_rseed_internal<R: RngCore>(
params: &P, zip212_enforcement: Zip212Enforcement,
height: BlockHeight,
rng: &mut R, rng: &mut R,
) -> Rseed { ) -> Rseed {
if params.is_nu_active(NetworkUpgrade::Canopy, height) { match zip212_enforcement {
let mut buffer = [0u8; 32]; Zip212Enforcement::Off => Rseed::BeforeZip212(jubjub::Fr::random(rng)),
rng.fill_bytes(&mut buffer); Zip212Enforcement::GracePeriod | Zip212Enforcement::On => {
Rseed::AfterZip212(buffer) let mut buffer = [0u8; 32];
} else { rng.fill_bytes(&mut buffer);
Rseed::BeforeZip212(jubjub::Fr::random(rng)) Rseed::AfterZip212(buffer)
}
} }
} }

View File

@ -158,7 +158,7 @@ pub struct Builder<'a, P, R> {
target_height: BlockHeight, target_height: BlockHeight,
expiry_height: BlockHeight, expiry_height: BlockHeight,
transparent_builder: TransparentBuilder, transparent_builder: TransparentBuilder,
sapling_builder: SaplingBuilder<P>, sapling_builder: SaplingBuilder,
orchard_builder: Option<orchard::builder::Builder>, orchard_builder: Option<orchard::builder::Builder>,
// TODO: In the future, instead of taking the spending keys as arguments when calling // TODO: In the future, instead of taking the spending keys as arguments when calling
// `add_sapling_spend` or `add_orchard_spend`, we will build an unauthorized, unproven // `add_sapling_spend` or `add_orchard_spend`, we will build an unauthorized, unproven
@ -261,13 +261,15 @@ impl<'a, P: consensus::Parameters, R: RngCore + CryptoRng> Builder<'a, P, R> {
target_height: BlockHeight, target_height: BlockHeight,
orchard_builder: Option<orchard::builder::Builder>, orchard_builder: Option<orchard::builder::Builder>,
) -> Self { ) -> Self {
let zip212_enforcement = consensus::sapling_zip212_enforcement(&params, target_height);
Builder { Builder {
params: params.clone(), params,
rng, rng,
target_height, target_height,
expiry_height: target_height + DEFAULT_TX_EXPIRY_DELTA, expiry_height: target_height + DEFAULT_TX_EXPIRY_DELTA,
transparent_builder: TransparentBuilder::empty(), transparent_builder: TransparentBuilder::empty(),
sapling_builder: SaplingBuilder::new(params, target_height), sapling_builder: SaplingBuilder::new(zip212_enforcement),
orchard_builder, orchard_builder,
sapling_asks: vec![], sapling_asks: vec![],
orchard_saks: Vec::new(), orchard_saks: Vec::new(),
@ -511,7 +513,7 @@ impl<'a, P: consensus::Parameters, R: RngCore + CryptoRng> Builder<'a, P, R> {
let mut rng = self.rng; let mut rng = self.rng;
let (sapling_bundle, tx_metadata) = match self let (sapling_bundle, tx_metadata) = match self
.sapling_builder .sapling_builder
.build::<SP, OP, _>(&mut rng, self.target_height) .build::<SP, OP, _>(&mut rng)
.map_err(Error::SaplingBuild)? .map_err(Error::SaplingBuild)?
.map(|(bundle, tx_metadata)| { .map(|(bundle, tx_metadata)| {
// We need to create proofs before signatures, because we still support // We need to create proofs before signatures, because we still support
@ -749,6 +751,7 @@ mod tests {
#[cfg(feature = "transparent-inputs")] #[cfg(feature = "transparent-inputs")]
use crate::{ use crate::{
legacy::keys::{AccountPrivKey, IncomingViewingKey}, legacy::keys::{AccountPrivKey, IncomingViewingKey},
sapling::note_encryption::Zip212Enforcement,
transaction::{ transaction::{
builder::{SaplingBuilder, DEFAULT_TX_EXPIRY_DELTA}, builder::{SaplingBuilder, DEFAULT_TX_EXPIRY_DELTA},
OutPoint, TxOut, OutPoint, TxOut,
@ -775,7 +778,7 @@ mod tests {
target_height: sapling_activation_height, target_height: sapling_activation_height,
expiry_height: sapling_activation_height + DEFAULT_TX_EXPIRY_DELTA, expiry_height: sapling_activation_height + DEFAULT_TX_EXPIRY_DELTA,
transparent_builder: TransparentBuilder::empty(), transparent_builder: TransparentBuilder::empty(),
sapling_builder: SaplingBuilder::new(TEST_NETWORK, sapling_activation_height), sapling_builder: SaplingBuilder::new(Zip212Enforcement::Off),
#[cfg(feature = "zfuture")] #[cfg(feature = "zfuture")]
tze_builder: TzeBuilder::empty(), tze_builder: TzeBuilder::empty(),
#[cfg(not(feature = "zfuture"))] #[cfg(not(feature = "zfuture"))]