mirror of https://github.com/zcash/orchard.git
Merge pull request #348 from jarys/circuit-constructor
Add `Circuit::from_action_context` constructor
This commit is contained in:
commit
75ed8cd806
|
@ -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
|
||||
|
|
|
@ -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(¬e.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(¬e.rho())),
|
||||
rcm_new: Value::known(note.rseed().rcm(¬e.rho())),
|
||||
rcv: Value::known(self.rcv),
|
||||
},
|
||||
Circuit::from_action_context_unchecked(self.spend, note, alpha, self.rcv),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue