Merge pull request #348 from jarys/circuit-constructor

Add `Circuit::from_action_context` constructor
This commit is contained in:
str4d 2022-09-26 15:39:09 +01:00 committed by GitHub
commit 75ed8cd806
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 97 additions and 37 deletions

View File

@ -13,6 +13,8 @@ and this project adheres to Rust's notion of
- `orchard::note`:
- `RandomSeed`
- `Note::{from_parts, rseed}`
- `orchard::builder::SpendInfo::new`
- `orchard::circuit::Circuit::from_action_context`
## [0.2.0] - 2022-06-24
### Added

View File

@ -4,7 +4,6 @@ use core::fmt;
use core::iter;
use ff::Field;
use halo2_proofs::circuit::Value;
use nonempty::NonEmpty;
use pasta_curves::pallas;
use rand::{prelude::SliceRandom, CryptoRng, RngCore};
@ -58,15 +57,35 @@ impl From<value::OverflowError> for Error {
/// Information about a specific note to be spent in an [`Action`].
#[derive(Debug)]
struct SpendInfo {
dummy_sk: Option<SpendingKey>,
fvk: FullViewingKey,
scope: Scope,
note: Note,
merkle_path: MerklePath,
pub struct SpendInfo {
pub(crate) dummy_sk: Option<SpendingKey>,
pub(crate) fvk: FullViewingKey,
pub(crate) scope: Scope,
pub(crate) note: Note,
pub(crate) merkle_path: MerklePath,
}
impl SpendInfo {
/// This constructor is public to enable creation of custom builders.
/// If you are not creating a custom builder, use [`Builder::add_spend`] instead.
///
/// Creates a `SpendInfo` from note, full viewing key owning the note,
/// and merkle path witness of the note.
///
/// Returns `None` if the `fvk` does not own the `note`.
///
/// [`Builder::add_spend`]: Builder::add_spend
pub fn new(fvk: FullViewingKey, note: Note, merkle_path: MerklePath) -> Option<Self> {
let scope = fvk.scope_for_address(&note.recipient())?;
Some(SpendInfo {
dummy_sk: None,
fvk,
scope,
note,
merkle_path,
})
}
/// Defined in [Zcash Protocol Spec § 4.8.3: Dummy Notes (Orchard)][orcharddummynotes].
///
/// [orcharddummynotes]: https://zips.z.cash/protocol/nu5.pdf#orcharddummynotes
@ -144,10 +163,6 @@ impl ActionInfo {
let cv_net = ValueCommitment::derive(v_net, self.rcv.clone());
let nf_old = self.spend.note.nullifier(&self.spend.fvk);
let sender_address = self.spend.note.recipient();
let rho_old = self.spend.note.rho();
let psi_old = self.spend.note.rseed().psi(&rho_old);
let rcm_old = self.spend.note.rseed().rcm(&rho_old);
let ak: SpendValidatingKey = self.spend.fvk.clone().into();
let alpha = pallas::Scalar::random(&mut rng);
let rk = ak.randomize(&alpha);
@ -182,33 +197,10 @@ impl ActionInfo {
cv_net,
SigningMetadata {
dummy_ask: self.spend.dummy_sk.as_ref().map(SpendAuthorizingKey::from),
parts: SigningParts {
ak: ak.clone(),
alpha,
},
parts: SigningParts { ak, alpha },
},
),
Circuit {
path: Value::known(self.spend.merkle_path.auth_path()),
pos: Value::known(self.spend.merkle_path.position()),
g_d_old: Value::known(sender_address.g_d()),
pk_d_old: Value::known(*sender_address.pk_d()),
v_old: Value::known(self.spend.note.value()),
rho_old: Value::known(rho_old),
psi_old: Value::known(psi_old),
rcm_old: Value::known(rcm_old),
cm_old: Value::known(self.spend.note.commitment()),
alpha: Value::known(alpha),
ak: Value::known(ak),
nk: Value::known(*self.spend.fvk.nk()),
rivk: Value::known(self.spend.fvk.rivk(self.spend.scope)),
g_d_new: Value::known(note.recipient().g_d()),
pk_d_new: Value::known(*note.recipient().pk_d()),
v_new: Value::known(note.value()),
psi_new: Value::known(note.rseed().psi(&note.rho())),
rcm_new: Value::known(note.rseed().rcm(&note.rho())),
rcv: Value::known(self.rcv),
},
Circuit::from_action_context_unchecked(self.spend, note, alpha, self.rcv),
)
}
}

View File

@ -25,6 +25,7 @@ use self::{
note_commit::{NoteCommitChip, NoteCommitConfig},
};
use crate::{
builder::SpendInfo,
constants::{
OrchardCommitDomains, OrchardFixedBases, OrchardFixedBasesFull, OrchardHashDomains,
MERKLE_DEPTH_ORCHARD,
@ -35,7 +36,7 @@ use crate::{
note::{
commitment::{NoteCommitTrapdoor, NoteCommitment},
nullifier::Nullifier,
ExtractedNoteCommitment,
ExtractedNoteCommitment, Note,
},
primitives::redpallas::{SpendAuth, VerificationKey},
spec::NonIdentityPallasPoint,
@ -120,6 +121,71 @@ pub struct Circuit {
pub(crate) rcv: Value<ValueCommitTrapdoor>,
}
impl Circuit {
/// This constructor is public to enable creation of custom builders.
/// If you are not creating a custom builder, use [`Builder`] to compose
/// and authorize a transaction.
///
/// Constructs a `Circuit` from the following components:
/// - `spend`: [`SpendInfo`] of the note spent in scope of the action
/// - `output_note`: a note created in scope of the action
/// - `alpha`: a scalar used for randomization of the action spend validating key
/// - `rcv`: trapdoor for the action value commitment
///
/// Returns `None` if the `rho` of the `output_note` is not equal
/// to the nullifier of the spent note.
///
/// [`SpendInfo`]: crate::builder::SpendInfo
/// [`Builder`]: crate::builder::Builder
pub fn from_action_context(
spend: SpendInfo,
output_note: Note,
alpha: pallas::Scalar,
rcv: ValueCommitTrapdoor,
) -> Option<Circuit> {
(spend.note.nullifier(&spend.fvk) == output_note.rho())
.then(|| Self::from_action_context_unchecked(spend, output_note, alpha, rcv))
}
pub(crate) fn from_action_context_unchecked(
spend: SpendInfo,
output_note: Note,
alpha: pallas::Scalar,
rcv: ValueCommitTrapdoor,
) -> Circuit {
let sender_address = spend.note.recipient();
let rho_old = spend.note.rho();
let psi_old = spend.note.rseed().psi(&rho_old);
let rcm_old = spend.note.rseed().rcm(&rho_old);
let rho_new = output_note.rho();
let psi_new = output_note.rseed().psi(&rho_new);
let rcm_new = output_note.rseed().rcm(&rho_new);
Circuit {
path: Value::known(spend.merkle_path.auth_path()),
pos: Value::known(spend.merkle_path.position()),
g_d_old: Value::known(sender_address.g_d()),
pk_d_old: Value::known(*sender_address.pk_d()),
v_old: Value::known(spend.note.value()),
rho_old: Value::known(rho_old),
psi_old: Value::known(psi_old),
rcm_old: Value::known(rcm_old),
cm_old: Value::known(spend.note.commitment()),
alpha: Value::known(alpha),
ak: Value::known(spend.fvk.clone().into()),
nk: Value::known(*spend.fvk.nk()),
rivk: Value::known(spend.fvk.rivk(spend.scope)),
g_d_new: Value::known(output_note.recipient().g_d()),
pk_d_new: Value::known(*output_note.recipient().pk_d()),
v_new: Value::known(output_note.value()),
psi_new: Value::known(psi_new),
rcm_new: Value::known(rcm_new),
rcv: Value::known(rcv),
}
}
}
impl plonk::Circuit<pallas::Base> for Circuit {
type Config = Config;
type FloorPlanner = floor_planner::V1;