Skip to content

Commit

Permalink
Merge branch 'zsa1' into update_book
Browse files Browse the repository at this point in the history
  • Loading branch information
ConstanceBeguier authored Jan 2, 2025
2 parents bf897e7 + 3d2515b commit fb643b6
Show file tree
Hide file tree
Showing 17 changed files with 339 additions and 124 deletions.
2 changes: 1 addition & 1 deletion benches/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ fn criterion_benchmark<FL: OrchardFlavorBench>(c: &mut Criterion) {
)
.unwrap();
}
let bundle: Bundle<_, i64, FL> = builder.build(rng).unwrap().unwrap().0;
let bundle: Bundle<_, i64, FL> = builder.build(rng).unwrap().0;

let instances: Vec<_> = bundle
.actions()
Expand Down
2 changes: 1 addition & 1 deletion benches/note_decryption.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ fn bench_note_decryption<FL: OrchardFlavorBench>(c: &mut Criterion) {
None,
)
.unwrap();
let bundle: Bundle<_, i64, FL> = builder.build(rng).unwrap().unwrap().0;
let bundle: Bundle<_, i64, FL> = builder.build(rng).unwrap().0;
bundle
.create_proof(&pk, rng)
.unwrap()
Expand Down
47 changes: 22 additions & 25 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ impl SpendInfo {
///
/// Defined in [Transfer and Burn of Zcash Shielded Assets ZIP-0226 § Split Notes (DRAFT PR)][TransferZSA].
///
/// [TransferZSA]: https://qed-it.github.io/zips/zip-0226.html#split-notes
/// [TransferZSA]: https://zips.z.cash/zip-0226#split-notes
fn create_split_spend(&self, rng: &mut impl RngCore) -> Self {
SpendInfo {
dummy_sk: None,
Expand Down Expand Up @@ -654,7 +654,7 @@ impl Builder {
pub fn build<V: TryFrom<i64>, FL: OrchardFlavor>(
self,
rng: impl RngCore,
) -> Result<Option<UnauthorizedBundleWithMetadata<V, FL>>, BuildError> {
) -> Result<UnauthorizedBundleWithMetadata<V, FL>, BuildError> {
bundle(
rng,
self.anchor,
Expand Down Expand Up @@ -745,7 +745,7 @@ pub fn bundle<V: TryFrom<i64>, FL: OrchardFlavor>(
spends: Vec<SpendInfo>,
outputs: Vec<OutputInfo>,
burn: HashMap<AssetBase, NoteValue>,
) -> Result<Option<UnauthorizedBundleWithMetadata<V, FL>>, BuildError> {
) -> Result<UnauthorizedBundleWithMetadata<V, FL>, BuildError> {
let flags = bundle_type.flags();

let num_requested_spends = spends.len();
Expand Down Expand Up @@ -884,31 +884,30 @@ pub fn bundle<V: TryFrom<i64>, FL: OrchardFlavor>(
let bvk = derive_bvk(&actions, native_value_balance, burn.iter().cloned());
assert_eq!(redpallas::VerificationKey::from(&bsk), bvk);

Ok(NonEmpty::from_vec(actions).map(|actions| {
(
Bundle::from_parts(
actions,
flags,
result_value_balance,
burn,
anchor,
InProgress {
proof: Unproven {
witnesses,
circuit_flavor: FL::FLAVOR,
},
sigs: Unauthorized { bsk },
Ok((
Bundle::from_parts(
// `actions` is never empty. It contains at least MIN_ACTIONS=2 actions.
NonEmpty::from_vec(actions).unwrap(),
flags,
result_value_balance,
burn,
anchor,
InProgress {
proof: Unproven {
witnesses,
circuit_flavor: FL::FLAVOR,
},
),
bundle_meta,
)
}))
sigs: Unauthorized { bsk },
},
),
bundle_meta,
))
}

/// Marker trait representing bundle signatures in the process of being created.
pub trait InProgressSignatures: fmt::Debug {
/// The authorization type of an Orchard action in the process of being authorized.
type SpendAuth: fmt::Debug;
type SpendAuth: fmt::Debug + Clone;
}

/// Marker for a bundle in the process of being built.
Expand Down Expand Up @@ -1053,7 +1052,7 @@ impl InProgressSignatures for PartiallyAuthorized {
/// A heisen[`Signature`] for a particular [`Action`].
///
/// [`Signature`]: redpallas::Signature
#[derive(Debug)]
#[derive(Debug, Clone)]
pub enum MaybeSigned {
/// The information needed to sign this [`Action`].
SigningMetadata(SigningParts),
Expand Down Expand Up @@ -1302,7 +1301,6 @@ pub mod testing {
builder
.build(&mut self.rng)
.unwrap()
.unwrap()
.0
.create_proof(&pk, &mut self.rng)
.unwrap()
Expand Down Expand Up @@ -1434,7 +1432,6 @@ mod tests {
let bundle: Bundle<Authorized, i64, FL> = builder
.build(&mut rng)
.unwrap()
.unwrap()
.0
.create_proof(&pk, &mut rng)
.unwrap()
Expand Down
3 changes: 1 addition & 2 deletions src/bundle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ impl Flags {
/// Defines the authorization type of an Orchard bundle.
pub trait Authorization: fmt::Debug {
/// The authorization type of an Orchard action.
type SpendAuth: fmt::Debug;
type SpendAuth: fmt::Debug + Clone;
}

/// A bundle of actions to be applied to the ledger.
Expand Down Expand Up @@ -457,7 +457,6 @@ pub(crate) fn derive_bvk<'a, A: 'a, V: Clone + Into<i64>, FL: 'a + OrchardFlavor
value_balance: V,
burn: impl Iterator<Item = (AssetBase, NoteValue)>,
) -> redpallas::VerificationKey<Binding> {
// https://p.z.cash/TCR:bad-txns-orchard-binding-signature-invalid?partial
(actions
.into_iter()
.map(|a| a.cv_net())
Expand Down
6 changes: 3 additions & 3 deletions src/bundle/commitments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,15 @@ pub fn hash_bundle_auth_empty() -> Blake2bHash {
/// Construct the commitment for an absent issue bundle as defined in
/// [ZIP-227: Issuance of Zcash Shielded Assets][zip227]
///
/// [zip227]: https://qed-it.github.io/zips/zip-0227
/// [zip227]: https://zips.z.cash/zip-0227
pub fn hash_issue_bundle_auth_empty() -> Blake2bHash {
hasher(ZCASH_ORCHARD_ZSA_ISSUE_SIG_PERSONALIZATION).finalize()
}

/// Construct the commitment for an absent issue bundle as defined in
/// [ZIP-227: Issuance of Zcash Shielded Assets][zip227]
///
/// [zip227]: https://qed-it.github.io/zips/zip-0227
/// [zip227]: https://zips.z.cash/zip-0227
pub fn hash_issue_bundle_txid_empty() -> Blake2bHash {
hasher(ZCASH_ORCHARD_ZSA_ISSUE_PERSONALIZATION).finalize()
}
Expand Down Expand Up @@ -166,7 +166,7 @@ mod tests {
)
.unwrap();

builder.build::<i64, FL>(rng).unwrap().unwrap().0
builder.build::<i64, FL>(rng).unwrap().0
}

/// Verify that the hash for an Orchard Vanilla bundle matches a fixed reference value
Expand Down
40 changes: 29 additions & 11 deletions src/circuit/circuit_zsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,22 @@ impl OrchardCircuit for OrchardZSA {
meta.advice_column(),
];

// The new or updated constraints for OrchardZSA are explained in
// [ZIP-226: Transfer and Burn of Zcash Shielded Assets][circuitstatement].
//
// All OrchardZSA constraints:
// Constrain split_flag to be boolean
// Constrain v_old * (1 - split_flag) - v_new = magnitude * sign (https://p.z.cash/ZKS:action-cv-net-integrity?partial).
// Constrain (v_old = 0 and is_native_asset = 1) or (calculated root = anchor) (https://p.z.cash/ZKS:action-merkle-path-validity?partial).
// Constrain v_old = 0 or enable_spends = 1 (https://p.z.cash/ZKS:action-enable-spend).
// Constrain v_new = 0 or enable_outputs = 1 (https://p.z.cash/ZKS:action-enable-output).
// Constrain v_old * (1 - split_flag) - v_new = magnitude * sign
// Constrain (v_old = 0 and is_native_asset = 1) or (calculated root = anchor)
// Constrain v_old = 0 or enable_spends = 1
// Constrain v_new = 0 or enable_outputs = 1
// Constrain is_native_asset to be boolean
// Constraint if is_native_asset = 1 then asset = native_asset else asset != native_asset
// Constraint if split_flag = 0 then psi_old = psi_nf
// Constraint if split_flag = 1, then is_native_asset = 0
// Constraint if enable_zsa = 0, then is_native_asset = 1
//
// [circuitstatement]: https://zips.z.cash/zip-0226#circuit-statement
let q_orchard = meta.selector();
meta.create_gate("Orchard circuit checks", |meta| {
let q_orchard = meta.query_selector(q_orchard);
Expand Down Expand Up @@ -426,7 +432,7 @@ impl OrchardCircuit for OrchardZSA {
circuit.asset,
)?;

// Merkle path validity check (https://p.z.cash/ZKS:action-merkle-path-validity?partial).
// Merkle path validity check.
let root = {
let path = circuit
.path
Expand All @@ -441,7 +447,10 @@ impl OrchardCircuit for OrchardZSA {
merkle_inputs.calculate_root(layouter.namespace(|| "Merkle path"), leaf)?
};

// Value commitment integrity (https://p.z.cash/ZKS:action-cv-net-integrity?partial).
// Value commitment integrity.
// See [ZIP-226: Transfer and Burn of Zcash Shielded Assets][valuecommitcorrectness] for more details.
//
// [valuecommitcorrectness]: https://zips.z.cash/zip-0226#value-commitment-correctness
let v_net_magnitude_sign = {
// Witness the magnitude and sign of v_net = v_old - v_new
let v_net_magnitude_sign = {
Expand Down Expand Up @@ -508,7 +517,10 @@ impl OrchardCircuit for OrchardZSA {
v_net_magnitude_sign
};

// Nullifier integrity (https://p.z.cash/ZKS:action-nullifier-integrity).
// Nullifier integrity.
// See [ZIP-226: Transfer and Burn of Zcash Shielded Assets][zip226] for more details.
//
// [zip226]: https://zips.z.cash/zip-0226
let nf_old = {
let nf_old = derive_nullifier(
&mut layouter.namespace(|| "nf_old = DeriveNullifier_nk(rho_old, psi_nf, cm_old)"),
Expand All @@ -531,7 +543,7 @@ impl OrchardCircuit for OrchardZSA {
nf_old
};

// Spend authority (https://p.z.cash/ZKS:action-spend-authority)
// Spend authority
{
let alpha = ScalarFixed::new(
ecc_chip.clone(),
Expand All @@ -554,7 +566,7 @@ impl OrchardCircuit for OrchardZSA {
layouter.constrain_instance(rk.inner().y().cell(), config.primary, RK_Y)?;
}

// Diversified address integrity (https://p.z.cash/ZKS:action-addr-integrity?partial).
// Diversified address integrity.
let pk_d_old = {
let ivk = {
let ak = ak_P.extract_p().inner().clone();
Expand Down Expand Up @@ -602,7 +614,10 @@ impl OrchardCircuit for OrchardZSA {
pk_d_old
};

// Old note commitment integrity (https://p.z.cash/ZKS:action-cm-old-integrity?partial).
// Old note commitment integrity.
// See [ZIP-226: Transfer and Burn of Zcash Shielded Assets][notecommit] for more details.
//
// [notecommit]: https://zips.z.cash/zip-0226#note-structure-commitment.
{
let rcm_old = ScalarFixed::new(
ecc_chip.clone(),
Expand Down Expand Up @@ -635,7 +650,10 @@ impl OrchardCircuit for OrchardZSA {
derived_cm_old.constrain_equal(layouter.namespace(|| "cm_old equality"), &cm_old)?;
}

// New note commitment integrity (https://p.z.cash/ZKS:action-cmx-new-integrity?partial).
// New note commitment integrity.
// See [ZIP-226: Transfer and Burn of Zcash Shielded Assets][notecommit] for more details.
//
// [notecommit]: https://zips.z.cash/zip-0226#note-structure-commitment.
{
// Witness g_d_new
let g_d_new = {
Expand Down
8 changes: 2 additions & 6 deletions src/circuit/note_commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -718,8 +718,6 @@ impl<Lookup: PallasLookupRangeCheck> DecomposeHVanilla<Lookup> {
/// --------------------------------------------
/// | h_zec | h_0 | h_1 | 1 |
/// | h_zsa | h_2_zsa | | 0 |
///
/// <https://p.z.cash/orchard-0.1:note-commit-decomposition-h?partial>
#[derive(Clone, Debug)]
struct DecomposeHZsa<Lookup: PallasLookupRangeCheck> {
q_notecommit_h: Selector,
Expand Down Expand Up @@ -879,8 +877,6 @@ impl<Lookup: PallasLookupRangeCheck> DecomposeHZsa<Lookup> {
/// | A_6 | A_7 | A_8 | q_notecommit_j |
/// ------------------------------------
/// | j | j_0 | j_1 | 1 |
///
/// https://p.z.cash/orchard-0.1:note-commit-decomposition-j?partial
#[derive(Clone, Debug)]
struct DecomposeJ<Lookup: PallasLookupRangeCheck> {
q_notecommit_j: Selector,
Expand Down Expand Up @@ -2099,8 +2095,8 @@ pub(in crate::circuit) mod gadgets {
// constraints allows ⊥ to occur, and then during synthesis it detects these edge
// cases and raises an error (aborting proof creation).
//
// https://p.z.cash/ZKS:action-cm-old-integrity?partial
// https://p.z.cash/ZKS:action-cmx-new-integrity?partial
// See [ZIP-226: Transfer and Burn of Zcash Shielded Assets][zip226] for more details.
// [zip226]: https://zips.z.cash/zip-0226#note-structure-commitment.
let message_common_prefix = Message::from_pieces(
chip.clone(),
vec![
Expand Down
4 changes: 2 additions & 2 deletions src/circuit/value_commit_orchard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ pub(in crate::circuit) mod gadgets {
plonk,
};

/// `ValueCommit^Orchard` from [Section 5.4.8.3 Homomorphic Pedersen commitments (Sapling and Orchard)].
/// `ValueCommit^Orchard` from [ZIP-226: Transfer and Burn of Zcash Shielded Assets][zip226].
///
/// [Section 5.4.8.3 Homomorphic Pedersen commitments (Sapling and Orchard)]: https://zips.z.cash/protocol/protocol.pdf#concretehomomorphiccommit
/// [zip226]: https://zips.z.cash/zip-0226#value-commitment-correctness
pub(in crate::circuit) fn value_commit_orchard<Lookup: PallasLookupRangeCheck>(
mut layouter: impl Layouter<pallas::Base>,
ecc_chip: EccChip<OrchardFixedBases, Lookup>,
Expand Down
1 change: 1 addition & 0 deletions src/constants.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Constants used in the Orchard protocol.
pub mod fixed_bases;
pub mod reference_keys;
pub mod sinsemilla;
pub mod util;

Expand Down
54 changes: 54 additions & 0 deletions src/constants/reference_keys.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//! Orchard reference keys, including the spending key and recipient address, used for reference notes.
//!
//! The reference SpendingKey is a placeholder key with all bytes set to zero.
//! Using this SpendingKey, we derive the FullViewingKey, and the recipient address.
//! To avoid repeating the derivation process whenever the recipient address is required, we store
//! its raw encoding.
use crate::{
address::Address,
keys::{FullViewingKey, SpendingKey},
};

/// Raw bytes representation of the reference recipient address.
pub const RAW_REFERENCE_RECIPIENT: [u8; 43] = [
204, 54, 96, 25, 89, 33, 59, 107, 12, 219, 150, 167, 92, 23, 195, 166, 104, 169, 127, 13, 106,
140, 92, 225, 100, 165, 24, 234, 155, 169, 165, 14, 167, 81, 145, 253, 134, 27, 15, 241, 14,
98, 176,
];

/// Reference keys (spending key and recipient address) are used for reference notes.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct ReferenceKeys;

impl ReferenceKeys {
/// Returns the spending key for reference notes.
pub fn sk() -> SpendingKey {
SpendingKey::from_bytes([0; 32]).unwrap()
}

/// Returns the recipient address for reference notes.
pub fn recipient() -> Address {
Address::from_raw_address_bytes(&RAW_REFERENCE_RECIPIENT).unwrap()
}

/// Returns the full viewing key for reference notes.
pub fn fvk() -> FullViewingKey {
FullViewingKey::from(&Self::sk())
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::keys::{FullViewingKey, Scope};

#[test]
fn recipient() {
let sk = SpendingKey::from_bytes([0; 32]).unwrap();
let fvk = FullViewingKey::from(&sk);
let recipient = fvk.address_at(0u32, Scope::External);

assert_eq!(recipient, ReferenceKeys::recipient());
}
}
Loading

0 comments on commit fb643b6

Please sign in to comment.