diff --git a/src/builder.rs b/src/builder.rs index db8ba598..5a418271 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -12,7 +12,7 @@ use rand::{CryptoRng, RngCore}; use crate::{ address::Address, bundle::{Action, Authorization, Authorized, Bundle, Flags}, - circuit::{Circuit, Proof, ProvingKey}, + circuit::{Circuit, Instance, Proof, ProvingKey}, keys::{ FullViewingKey, OutgoingViewingKey, SpendAuthorizingKey, SpendValidatingKey, SpendingKey, }, @@ -284,8 +284,7 @@ impl Builder { fn build>( mut self, mut rng: impl RngCore, - pk: &ProvingKey, - ) -> Result, V>, Error> { + ) -> Result, V>, Error> { // Pair up the spends and recipients, extending with dummy values as necessary. // // TODO: Do we want to shuffle the order like we do for Sapling? And if we do, do @@ -348,20 +347,13 @@ impl Builder { .into_bvk(); assert_eq!(redpallas::VerificationKey::from(&bsk), bvk); - // Create the proof. - let instances: Vec<_> = actions - .iter() - .map(|a| a.to_instance(flags, anchor)) - .collect(); - let proof = Proof::create(pk, &circuits, &instances)?; - Ok(Bundle::from_parts( NonEmpty::from_vec(actions).unwrap(), flags, result_value_balance, anchor, InProgress { - proof, + proof: Unproven { circuits }, sigs: Unauthorized { bsk }, }, )) @@ -385,6 +377,47 @@ impl Authorization for InProgress { type SpendAuth = S::SpendAuth; } +/// Marker for a bundle without a proof. +/// +/// This struct contains the private data needed to create a [`Proof`] for a [`Bundle`]. +#[derive(Debug)] +pub struct Unproven { + circuits: Vec, +} + +impl InProgress { + /// Creates the proof for this bundle. + pub fn create_proof( + &self, + pk: &ProvingKey, + instances: &[Instance], + ) -> Result { + Proof::create(pk, &self.proof.circuits, instances) + } +} + +impl Bundle, V> { + /// Creates the proof for this bundle. + pub fn create_proof(self, pk: &ProvingKey) -> Result, V>, Error> { + let instances: Vec<_> = self + .actions() + .iter() + .map(|a| a.to_instance(*self.flags(), *self.anchor())) + .collect(); + self.try_authorize( + &mut (), + |_, _, a| Ok(a), + |_, auth| { + let proof = auth.create_proof(pk, &instances)?; + Ok(InProgress { + proof, + sigs: auth.sigs, + }) + }, + ) + } +} + /// The parts needed to sign an [`Action`]. #[derive(Debug)] pub struct SigningParts { @@ -595,7 +628,9 @@ pub mod testing { let pk = ProvingKey::build(); builder - .build(&mut self.rng, &pk) + .build(&mut self.rng) + .unwrap() + .create_proof(&pk) .unwrap() .prepare(&mut self.rng, [0; 32]) .sign(&mut self.rng, &SpendAuthorizingKey::from(&self.sk)) @@ -679,7 +714,9 @@ mod tests { .add_recipient(None, recipient, NoteValue::from_raw(5000), None) .unwrap(); let bundle: Bundle = builder - .build(&mut rng, &pk) + .build(&mut rng) + .unwrap() + .create_proof(&pk) .unwrap() .prepare(&mut rng, [0; 32]) .finalize()