Add the capability to generate dummy spends (internal to the Builder)
This commit is contained in:
parent
954a27ee9b
commit
6f02b62c8e
12
CHANGELOG.md
12
CHANGELOG.md
|
@ -26,6 +26,7 @@ The entries below are relative to the `zcash_primitives::sapling` module as of
|
|||
- `OutputInfo`
|
||||
- `ProverProgress`
|
||||
- `BundleType`
|
||||
- `SigningMetadata`
|
||||
- `bundle` bundle builder function.
|
||||
- `sapling_crypto::bundle` module:
|
||||
- The following types moved from
|
||||
|
@ -33,7 +34,7 @@ The entries below are relative to the `zcash_primitives::sapling` module as of
|
|||
- `Bundle`
|
||||
- `SpendDescription, SpendDescriptionV5`
|
||||
- `OutputDescription, OutputDescriptionV5`
|
||||
- `Authorization, Authorized, MapAuth`
|
||||
- `Authorization, Authorized`
|
||||
- `GrothProofBytes`
|
||||
- `Bundle::<InProgress<Unproven, _>>::create_proofs`
|
||||
- `Bundle::<InProgress<_, Unsigned>>::prepare`
|
||||
|
@ -42,9 +43,6 @@ The entries below are relative to the `zcash_primitives::sapling` module as of
|
|||
- `Bundle::<InProgress<Proven, Unsigned>>::apply_signatures`
|
||||
- `Bundle::try_map_authorization`
|
||||
- `TryMapAuth`
|
||||
- `impl {MapAuth, TryMapAuth} for (FnMut, FnMut, FnMut, FnMut)`
|
||||
helpers to enable calling `Bundle::{map_authorization, try_map_authorization}`
|
||||
with a set of closures.
|
||||
- `testing` module, containing the following functions moved from
|
||||
`zcash_primitives::transaction::components::sapling::testing`:
|
||||
- `arb_output_description`
|
||||
|
@ -93,6 +91,7 @@ The entries below are relative to the `zcash_primitives::sapling` module as of
|
|||
argument as a `NoteValue` instead of as a bare `u64`.
|
||||
- `sapling_crypto::builder`:
|
||||
- `SaplingBuilder` has been renamed to `Builder`
|
||||
- `MaybeSigned::SigningMetadata` has been renamed to `MaybeSigned::SigningParts`
|
||||
- `Builder` no longer has a `P: zcash_primitives::consensus::Parameters`
|
||||
type parameter.
|
||||
- `Builder::new` now takes a `Zip212Enforcement` argument instead of a
|
||||
|
@ -121,6 +120,9 @@ The entries below are relative to the `zcash_primitives::sapling` module as of
|
|||
- `Bundle` now has a second generic parameter `V`.
|
||||
- `Bundle::value_balance` now returns `&V` instead of
|
||||
`&zcash_primitives::transaction::components::Amount`.
|
||||
- `Bundle::map_authorization` now takes a context argument and explicit
|
||||
functions for each mappable field, rather than a `MapAuth` value, in
|
||||
order to simplify handling of context values.
|
||||
- `Authorized::binding_sig` now has type `redjubjub::Signature<Binding>`.
|
||||
- `Authorized::AuthSig` now has type `redjubjub::Signature<SpendAuth>`.
|
||||
- `SpendDescription::temporary_zcashd_from_parts` now takes `rk` as
|
||||
|
@ -131,7 +133,6 @@ The entries below are relative to the `zcash_primitives::sapling` module as of
|
|||
`redjubjub::Signature<SpendAuth>` instead of
|
||||
`sapling_crypto::redjubjub::Signature`.
|
||||
- `testing::arb_bundle` now takes a `value_balance: V` argument.
|
||||
- `MapAuth` trait methods now take `&mut self` instead of `&self`.
|
||||
- `sapling_crypto::circuit::ValueCommitmentOpening::value` is now represented as
|
||||
a `NoteValue` instead of as a bare `u64`.
|
||||
- `sapling_crypto::keys`:
|
||||
|
@ -175,6 +176,7 @@ The entries below are relative to the `zcash_primitives::sapling` module as of
|
|||
- `OutputDescription::read`
|
||||
- `OutputDescription::{write_v4, write_v5_without_proof}`
|
||||
- `OutputDescriptionV5::read`
|
||||
- `MapAuth` trait
|
||||
- `sapling_crypto::builder`:
|
||||
- `SpendDescriptionInfo`
|
||||
- `sapling_crypto::note_encryption::SaplingDomain::for_height` (use
|
||||
|
|
157
src/builder.rs
157
src/builder.rs
|
@ -4,14 +4,14 @@ use core::fmt;
|
|||
use std::{iter, marker::PhantomData};
|
||||
|
||||
use group::ff::Field;
|
||||
use incrementalmerkletree::Position;
|
||||
use rand::{seq::SliceRandom, RngCore};
|
||||
use rand_core::CryptoRng;
|
||||
use redjubjub::{Binding, SpendAuth};
|
||||
|
||||
use crate::{
|
||||
bundle::{
|
||||
Authorization, Authorized, Bundle, GrothProofBytes, MapAuth, OutputDescription,
|
||||
SpendDescription,
|
||||
Authorization, Authorized, Bundle, GrothProofBytes, OutputDescription, SpendDescription,
|
||||
},
|
||||
circuit,
|
||||
keys::{OutgoingViewingKey, SpendAuthorizingKey, SpendValidatingKey},
|
||||
|
@ -23,6 +23,7 @@ use crate::{
|
|||
},
|
||||
zip32::ExtendedSpendingKey,
|
||||
Anchor, Diversifier, MerklePath, Node, Note, PaymentAddress, ProofGenerationKey, SaplingIvk,
|
||||
NOTE_COMMITMENT_TREE_DEPTH,
|
||||
};
|
||||
|
||||
/// If there are any shielded inputs, always have at least two shielded outputs, padding
|
||||
|
@ -39,7 +40,7 @@ pub enum BundleType {
|
|||
/// with the minimum required outputs irrespective of whether any outputs have been
|
||||
/// requested; if no explicit outputs have been added, all of the outputs in the resulting
|
||||
/// bundle will be dummies.
|
||||
outputs_required: bool,
|
||||
bundle_required: bool,
|
||||
},
|
||||
/// A coinbase bundle is required to have no spends. No output padding is performed.
|
||||
Coinbase,
|
||||
|
@ -49,7 +50,7 @@ impl BundleType {
|
|||
/// The default bundle type has all flags enabled, and does not require a bundle to be produced
|
||||
/// if no spends or outputs have been added to the bundle.
|
||||
pub const DEFAULT: BundleType = BundleType::Transactional {
|
||||
outputs_required: false,
|
||||
bundle_required: false,
|
||||
};
|
||||
|
||||
/// Returns the number of logical outputs that a builder will produce in constructing a bundle
|
||||
|
@ -63,8 +64,8 @@ impl BundleType {
|
|||
num_outputs: usize,
|
||||
) -> Result<usize, &'static str> {
|
||||
match self {
|
||||
BundleType::Transactional { outputs_required } => {
|
||||
Ok(if *outputs_required || num_outputs > 0 {
|
||||
BundleType::Transactional { bundle_required } => {
|
||||
Ok(if *bundle_required || num_outputs > 0 {
|
||||
core::cmp::max(num_outputs, MIN_SHIELDED_OUTPUTS)
|
||||
} else {
|
||||
0
|
||||
|
@ -125,6 +126,7 @@ pub struct SpendInfo {
|
|||
proof_generation_key: ProofGenerationKey,
|
||||
note: Note,
|
||||
merkle_path: MerklePath,
|
||||
dummy_ask: Option<SpendAuthorizingKey>,
|
||||
}
|
||||
|
||||
impl SpendInfo {
|
||||
|
@ -138,6 +140,7 @@ impl SpendInfo {
|
|||
proof_generation_key,
|
||||
note,
|
||||
merkle_path,
|
||||
dummy_ask: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,6 +149,27 @@ impl SpendInfo {
|
|||
self.note.value()
|
||||
}
|
||||
|
||||
/// Defined in [Zcash Protocol Spec § 4.8.3: Dummy Notes (Sapling)][orcharddummynotes].
|
||||
///
|
||||
/// [orcharddummynotes]: https://zips.z.cash/protocol/nu5.pdf#orcharddummynotes
|
||||
fn dummy<R: RngCore>(mut rng: R) -> Self {
|
||||
let (sk, _, note) = Note::dummy(&mut rng);
|
||||
let merkle_path = MerklePath::from_parts(
|
||||
iter::repeat_with(|| Node::from_scalar(jubjub::Base::random(&mut rng)))
|
||||
.take(NOTE_COMMITMENT_TREE_DEPTH.into())
|
||||
.collect(),
|
||||
Position::from(rng.next_u64()),
|
||||
)
|
||||
.expect("The path length corresponds to the length of the generated vector.");
|
||||
|
||||
SpendInfo {
|
||||
proof_generation_key: sk.proof_generation_key(),
|
||||
note,
|
||||
merkle_path,
|
||||
dummy_ask: Some(sk.ask),
|
||||
}
|
||||
}
|
||||
|
||||
fn has_matching_anchor(&self, anchor: &Anchor) -> bool {
|
||||
if self.note.value() == NoteValue::ZERO {
|
||||
true
|
||||
|
@ -161,6 +185,7 @@ impl SpendInfo {
|
|||
note: self.note,
|
||||
merkle_path: self.merkle_path,
|
||||
rcv: ValueCommitTrapdoor::random(rng),
|
||||
dummy_ask: self.dummy_ask,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -171,6 +196,7 @@ struct PreparedSpendInfo {
|
|||
note: Note,
|
||||
merkle_path: MerklePath,
|
||||
rcv: ValueCommitTrapdoor,
|
||||
dummy_ask: Option<SpendAuthorizingKey>,
|
||||
}
|
||||
|
||||
impl PreparedSpendInfo {
|
||||
|
@ -213,7 +239,10 @@ impl PreparedSpendInfo {
|
|||
nullifier,
|
||||
rk,
|
||||
zkproof,
|
||||
SigningParts { ak, alpha },
|
||||
SigningMetadata {
|
||||
dummy_ask: self.dummy_ask,
|
||||
parts: SigningParts { ak, alpha },
|
||||
},
|
||||
))
|
||||
}
|
||||
}
|
||||
|
@ -742,17 +771,7 @@ impl<'a, SP: SpendProver, OP: OutputProver, R: RngCore, U: ProverProgress>
|
|||
self.progress_notifier
|
||||
.update(self.progress, self.total_progress);
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
'a,
|
||||
S: InProgressSignatures,
|
||||
SP: SpendProver,
|
||||
OP: OutputProver,
|
||||
R: RngCore,
|
||||
U: ProverProgress,
|
||||
> MapAuth<InProgress<Unproven, S>, InProgress<Proven, S>> for CreateProofs<'a, SP, OP, R, U>
|
||||
{
|
||||
fn map_spend_proof(&mut self, spend: circuit::Spend) -> GrothProofBytes {
|
||||
let proof = self.spend_prover.create_proof(spend, &mut self.rng);
|
||||
self.update_progress();
|
||||
|
@ -765,11 +784,10 @@ impl<
|
|||
OP::encode_proof(proof)
|
||||
}
|
||||
|
||||
fn map_auth_sig(&mut self, s: S::AuthSig) -> S::AuthSig {
|
||||
s
|
||||
}
|
||||
|
||||
fn map_authorization(&mut self, a: InProgress<Unproven, S>) -> InProgress<Proven, S> {
|
||||
fn map_authorization<S: InProgressSignatures>(
|
||||
&mut self,
|
||||
a: InProgress<Unproven, S>,
|
||||
) -> InProgress<Proven, S> {
|
||||
InProgress {
|
||||
sigs: a.sigs,
|
||||
_proof_state: PhantomData::default(),
|
||||
|
@ -788,13 +806,21 @@ impl<S: InProgressSignatures, V> Bundle<InProgress<Unproven, S>, V> {
|
|||
) -> Bundle<InProgress<Proven, S>, V> {
|
||||
let total_progress =
|
||||
self.shielded_spends().len() as u32 + self.shielded_outputs().len() as u32;
|
||||
self.map_authorization(CreateProofs::new(
|
||||
let mut cp = CreateProofs::new(
|
||||
spend_prover,
|
||||
output_prover,
|
||||
rng,
|
||||
progress_notifier,
|
||||
total_progress,
|
||||
))
|
||||
);
|
||||
|
||||
self.map_authorization(
|
||||
&mut cp,
|
||||
|cp, spend| cp.map_spend_proof(spend),
|
||||
|cp, output| cp.map_output_proof(output),
|
||||
|_cp, sig| sig,
|
||||
|cp, auth| cp.map_authorization(auth),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -811,7 +837,7 @@ impl fmt::Debug for Unsigned {
|
|||
}
|
||||
|
||||
impl InProgressSignatures for Unsigned {
|
||||
type AuthSig = SigningParts;
|
||||
type AuthSig = SigningMetadata;
|
||||
}
|
||||
|
||||
/// The parts needed to sign a [`SpendDescription`].
|
||||
|
@ -831,6 +857,18 @@ pub struct PartiallyAuthorized {
|
|||
sighash: [u8; 32],
|
||||
}
|
||||
|
||||
/// Container for metadata needed to sign a Sapling input.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SigningMetadata {
|
||||
/// If this action is spending a dummy note, this field holds that note's spend
|
||||
/// authorizing key.
|
||||
///
|
||||
/// These keys are used automatically in [`Bundle<Unauthorized>::prepare`] or
|
||||
/// [`Bundle<Unauthorized>::apply_signatures`] to sign dummy spends.
|
||||
dummy_ask: Option<SpendAuthorizingKey>,
|
||||
parts: SigningParts,
|
||||
}
|
||||
|
||||
impl InProgressSignatures for PartiallyAuthorized {
|
||||
type AuthSig = MaybeSigned;
|
||||
}
|
||||
|
@ -841,7 +879,7 @@ impl InProgressSignatures for PartiallyAuthorized {
|
|||
#[derive(Clone, Debug)]
|
||||
pub enum MaybeSigned {
|
||||
/// The information needed to sign this [`SpendDescription`].
|
||||
SigningMetadata(SigningParts),
|
||||
SigningParts(SigningParts),
|
||||
/// The signature for this [`SpendDescription`].
|
||||
Signature(redjubjub::Signature<SpendAuth>),
|
||||
}
|
||||
|
@ -864,18 +902,24 @@ impl<P: InProgressProofs, V> Bundle<InProgress<P, Unsigned>, V> {
|
|||
mut rng: R,
|
||||
sighash: [u8; 32],
|
||||
) -> Bundle<InProgress<P, PartiallyAuthorized>, V> {
|
||||
self.map_authorization((
|
||||
|proof| proof,
|
||||
|proof| proof,
|
||||
MaybeSigned::SigningMetadata,
|
||||
|auth: InProgress<P, Unsigned>| InProgress {
|
||||
self.map_authorization(
|
||||
&mut rng,
|
||||
|_, proof| proof,
|
||||
|_, proof| proof,
|
||||
|rng, SigningMetadata { dummy_ask, parts }| match dummy_ask {
|
||||
None => MaybeSigned::SigningParts(parts),
|
||||
Some(ask) => {
|
||||
MaybeSigned::Signature(ask.randomize(&parts.alpha).sign(rng, &sighash))
|
||||
}
|
||||
},
|
||||
|rng, auth: InProgress<P, Unsigned>| InProgress {
|
||||
sigs: PartiallyAuthorized {
|
||||
binding_signature: auth.sigs.bsk.sign(&mut rng, &sighash),
|
||||
binding_signature: auth.sigs.bsk.sign(rng, &sighash),
|
||||
sighash,
|
||||
},
|
||||
_proof_state: PhantomData::default(),
|
||||
},
|
||||
))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -906,17 +950,18 @@ impl<P: InProgressProofs, V> Bundle<InProgress<P, PartiallyAuthorized>, V> {
|
|||
pub fn sign<R: RngCore + CryptoRng>(self, mut rng: R, ask: &SpendAuthorizingKey) -> Self {
|
||||
let expected_ak = ask.into();
|
||||
let sighash = self.authorization().sigs.sighash;
|
||||
self.map_authorization((
|
||||
|proof| proof,
|
||||
|proof| proof,
|
||||
|maybe| match maybe {
|
||||
MaybeSigned::SigningMetadata(parts) if parts.ak == expected_ak => {
|
||||
MaybeSigned::Signature(ask.randomize(&parts.alpha).sign(&mut rng, &sighash))
|
||||
self.map_authorization(
|
||||
&mut rng,
|
||||
|_, proof| proof,
|
||||
|_, proof| proof,
|
||||
|rng, maybe| match maybe {
|
||||
MaybeSigned::SigningParts(parts) if parts.ak == expected_ak => {
|
||||
MaybeSigned::Signature(ask.randomize(&parts.alpha).sign(rng, &sighash))
|
||||
}
|
||||
s => s,
|
||||
},
|
||||
|partial| partial,
|
||||
))
|
||||
|_rng, partial| partial,
|
||||
)
|
||||
}
|
||||
|
||||
/// Appends externally computed [`redjubjub::Signature`]s.
|
||||
|
@ -934,24 +979,25 @@ impl<P: InProgressProofs, V> Bundle<InProgress<P, PartiallyAuthorized>, V> {
|
|||
fn append_signature(self, signature: &redjubjub::Signature<SpendAuth>) -> Result<Self, Error> {
|
||||
let sighash = self.authorization().sigs.sighash;
|
||||
let mut signature_valid_for = 0usize;
|
||||
let bundle = self.map_authorization((
|
||||
|proof| proof,
|
||||
|proof| proof,
|
||||
|maybe| match maybe {
|
||||
MaybeSigned::SigningMetadata(parts) => {
|
||||
let bundle = self.map_authorization(
|
||||
&mut signature_valid_for,
|
||||
|_, proof| proof,
|
||||
|_, proof| proof,
|
||||
|ctx, maybe| match maybe {
|
||||
MaybeSigned::SigningParts(parts) => {
|
||||
let rk = parts.ak.randomize(&parts.alpha);
|
||||
if rk.verify(&sighash, signature).is_ok() {
|
||||
signature_valid_for += 1;
|
||||
**ctx += 1;
|
||||
MaybeSigned::Signature(*signature)
|
||||
} else {
|
||||
// Signature isn't for this input.
|
||||
MaybeSigned::SigningMetadata(parts)
|
||||
MaybeSigned::SigningParts(parts)
|
||||
}
|
||||
}
|
||||
s => s,
|
||||
},
|
||||
|partial| partial,
|
||||
));
|
||||
|_, partial| partial,
|
||||
);
|
||||
match signature_valid_for {
|
||||
0 => Err(Error::InvalidExternalSignature),
|
||||
1 => Ok(bundle),
|
||||
|
@ -1028,13 +1074,10 @@ pub mod testing {
|
|||
let anchor = spendable_notes
|
||||
.first()
|
||||
.zip(commitment_trees.first())
|
||||
.map_or_else(
|
||||
|| Anchor::empty_tree(),
|
||||
|(note, tree)| {
|
||||
let node = Node::from_cmu(¬e.cmu());
|
||||
Anchor::from(*tree.root(node).inner())
|
||||
},
|
||||
);
|
||||
.map_or_else(Anchor::empty_tree, |(note, tree)| {
|
||||
let node = Node::from_cmu(¬e.cmu());
|
||||
Anchor::from(*tree.root(node).inner())
|
||||
});
|
||||
let mut builder = Builder::new(zip212_enforcement, BundleType::DEFAULT, anchor);
|
||||
let mut rng = StdRng::from_seed(rng_seed);
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use core::fmt::Debug;
|
||||
|
||||
use memuse::DynamicUsage;
|
||||
|
||||
use redjubjub::{Binding, SpendAuth};
|
||||
|
||||
use zcash_note_encryption::{
|
||||
|
@ -38,75 +39,6 @@ impl Authorization for Authorized {
|
|||
type AuthSig = redjubjub::Signature<SpendAuth>;
|
||||
}
|
||||
|
||||
/// A map from one bundle authorization to another.
|
||||
///
|
||||
/// For use with [`Bundle::map_authorization`].
|
||||
pub trait MapAuth<A: Authorization, B: Authorization> {
|
||||
fn map_spend_proof(&mut self, p: A::SpendProof) -> B::SpendProof;
|
||||
fn map_output_proof(&mut self, p: A::OutputProof) -> B::OutputProof;
|
||||
fn map_auth_sig(&mut self, s: A::AuthSig) -> B::AuthSig;
|
||||
fn map_authorization(&mut self, a: A) -> B;
|
||||
}
|
||||
|
||||
/// The identity map.
|
||||
///
|
||||
/// This can be used with [`Bundle::map_authorization`] when you want to map the
|
||||
/// authorization of a subset of a transaction's bundles (excluding the Sapling bundle) in
|
||||
/// a higher-level transaction type.
|
||||
impl MapAuth<Authorized, Authorized> for () {
|
||||
fn map_spend_proof(
|
||||
&mut self,
|
||||
p: <Authorized as Authorization>::SpendProof,
|
||||
) -> <Authorized as Authorization>::SpendProof {
|
||||
p
|
||||
}
|
||||
|
||||
fn map_output_proof(
|
||||
&mut self,
|
||||
p: <Authorized as Authorization>::OutputProof,
|
||||
) -> <Authorized as Authorization>::OutputProof {
|
||||
p
|
||||
}
|
||||
|
||||
fn map_auth_sig(
|
||||
&mut self,
|
||||
s: <Authorized as Authorization>::AuthSig,
|
||||
) -> <Authorized as Authorization>::AuthSig {
|
||||
s
|
||||
}
|
||||
|
||||
fn map_authorization(&mut self, a: Authorized) -> Authorized {
|
||||
a
|
||||
}
|
||||
}
|
||||
|
||||
/// A helper for implementing `MapAuth` with a set of closures.
|
||||
impl<A, B, F, G, H, I> MapAuth<A, B> for (F, G, H, I)
|
||||
where
|
||||
A: Authorization,
|
||||
B: Authorization,
|
||||
F: FnMut(A::SpendProof) -> B::SpendProof,
|
||||
G: FnMut(A::OutputProof) -> B::OutputProof,
|
||||
H: FnMut(A::AuthSig) -> B::AuthSig,
|
||||
I: FnMut(A) -> B,
|
||||
{
|
||||
fn map_spend_proof(&mut self, p: A::SpendProof) -> B::SpendProof {
|
||||
self.0(p)
|
||||
}
|
||||
|
||||
fn map_output_proof(&mut self, p: A::OutputProof) -> B::OutputProof {
|
||||
self.1(p)
|
||||
}
|
||||
|
||||
fn map_auth_sig(&mut self, s: A::AuthSig) -> B::AuthSig {
|
||||
self.2(s)
|
||||
}
|
||||
|
||||
fn map_authorization(&mut self, a: A) -> B {
|
||||
self.3(a)
|
||||
}
|
||||
}
|
||||
|
||||
/// A fallible map from one bundle authorization to another.
|
||||
///
|
||||
/// For use with [`Bundle::try_map_authorization`].
|
||||
|
@ -200,7 +132,14 @@ impl<A: Authorization, V> Bundle<A, V> {
|
|||
}
|
||||
|
||||
/// Transitions this bundle from one authorization state to another.
|
||||
pub fn map_authorization<B: Authorization, F: MapAuth<A, B>>(self, mut f: F) -> Bundle<B, V> {
|
||||
pub fn map_authorization<R, B: Authorization>(
|
||||
self,
|
||||
mut context: R,
|
||||
mut spend_proof: impl FnMut(&mut R, A::SpendProof) -> B::SpendProof,
|
||||
mut output_proof: impl FnMut(&mut R, A::OutputProof) -> B::OutputProof,
|
||||
mut auth_sig: impl FnMut(&mut R, A::AuthSig) -> B::AuthSig,
|
||||
mut auth: impl FnMut(&mut R, A) -> B,
|
||||
) -> Bundle<B, V> {
|
||||
Bundle {
|
||||
shielded_spends: self
|
||||
.shielded_spends
|
||||
|
@ -210,8 +149,8 @@ impl<A: Authorization, V> Bundle<A, V> {
|
|||
anchor: d.anchor,
|
||||
nullifier: d.nullifier,
|
||||
rk: d.rk,
|
||||
zkproof: f.map_spend_proof(d.zkproof),
|
||||
spend_auth_sig: f.map_auth_sig(d.spend_auth_sig),
|
||||
zkproof: spend_proof(&mut context, d.zkproof),
|
||||
spend_auth_sig: auth_sig(&mut context, d.spend_auth_sig),
|
||||
})
|
||||
.collect(),
|
||||
shielded_outputs: self
|
||||
|
@ -223,11 +162,11 @@ impl<A: Authorization, V> Bundle<A, V> {
|
|||
ephemeral_key: o.ephemeral_key,
|
||||
enc_ciphertext: o.enc_ciphertext,
|
||||
out_ciphertext: o.out_ciphertext,
|
||||
zkproof: f.map_output_proof(o.zkproof),
|
||||
zkproof: output_proof(&mut context, o.zkproof),
|
||||
})
|
||||
.collect(),
|
||||
value_balance: self.value_balance,
|
||||
authorization: f.map_authorization(self.authorization),
|
||||
authorization: auth(&mut context, self.authorization),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
27
src/note.rs
27
src/note.rs
|
@ -2,6 +2,11 @@ use group::{ff::Field, GroupEncoding};
|
|||
use rand_core::{CryptoRng, RngCore};
|
||||
use zcash_spec::PrfExpand;
|
||||
|
||||
use crate::{
|
||||
keys::{ExpandedSpendingKey, FullViewingKey},
|
||||
zip32::ExtendedSpendingKey,
|
||||
};
|
||||
|
||||
use super::{
|
||||
keys::EphemeralSecretKey, value::NoteValue, Nullifier, NullifierDerivingKey, PaymentAddress,
|
||||
};
|
||||
|
@ -148,6 +153,28 @@ impl Note {
|
|||
))),
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates a dummy spent note.
|
||||
///
|
||||
/// Defined in [Zcash Protocol Spec § 4.8.2: Dummy Notes (Sapling)][saplingdummynotes].
|
||||
///
|
||||
/// [saplingdummynotes]: https://zips.z.cash/protocol/nu5.pdf#saplingdummynotes
|
||||
pub(crate) fn dummy<R: RngCore>(mut rng: R) -> (ExpandedSpendingKey, FullViewingKey, Self) {
|
||||
let mut sk_bytes = [0; 32];
|
||||
rng.fill_bytes(&mut sk_bytes);
|
||||
|
||||
let extsk = ExtendedSpendingKey::master(&sk_bytes[..]);
|
||||
let fvk = extsk.to_diversifiable_full_viewing_key().fvk().clone();
|
||||
let recipient = extsk.default_address();
|
||||
|
||||
let mut rseed_bytes = [0; 32];
|
||||
rng.fill_bytes(&mut rseed_bytes);
|
||||
let rseed = Rseed::AfterZip212(rseed_bytes);
|
||||
|
||||
let note = Note::from_parts(recipient.1, NoteValue::ZERO, rseed);
|
||||
|
||||
(extsk.expsk, fvk, note)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-dependencies"))]
|
||||
|
|
Loading…
Reference in New Issue