mirror of https://github.com/zcash/orchard.git
Circuit: Add enable_zsa flag (#79)
When enable_zsa flag is set to false, it is not possible to perform ZSA transactions (the circuit will fail). Fix the version of reddsa (=0.5.0) because recent versions required rust version 1.65 or newer Fix the version of tempfile (=3.5.0) because recent versions required rust version 1.63 or newer Limit the version of flate2 (<1.0.27) because recent versions raise some clippy issues
This commit is contained in:
parent
081513b363
commit
139ecca079
|
@ -35,9 +35,10 @@ hex = "0.4"
|
|||
lazy_static = "1"
|
||||
memuse = { version = "0.2.1", features = ["nonempty"] }
|
||||
pasta_curves = "0.5"
|
||||
tempfile = "= 3.5.0" # Last version required rust 1.63
|
||||
proptest = { version = "1.0.0", optional = true }
|
||||
rand = "0.8"
|
||||
reddsa = "0.5"
|
||||
reddsa = "=0.5.0" # Last version required rust 1.65
|
||||
nonempty = "0.7"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
subtle = "2.3"
|
||||
|
@ -49,6 +50,7 @@ tracing = "0.1"
|
|||
|
||||
# Developer tooling dependencies
|
||||
image = { version = ">= 0.24, < 0.24.5", optional = true } # 0.24.5 has MSRV 1.61
|
||||
flate2 = ">= 1.0, <1.0.27" # Clippy issues in last version
|
||||
plotters = { version = "0.3.0", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
|
|
|
@ -28,7 +28,7 @@ fn criterion_benchmark(c: &mut Criterion) {
|
|||
|
||||
let create_bundle = |num_recipients| {
|
||||
let mut builder = Builder::new(
|
||||
Flags::from_parts(true, true),
|
||||
Flags::from_parts(true, true, false),
|
||||
Anchor::from_bytes([0; 32]).unwrap(),
|
||||
);
|
||||
for _ in 0..num_recipients {
|
||||
|
|
|
@ -47,7 +47,7 @@ fn bench_note_decryption(c: &mut Criterion) {
|
|||
|
||||
let bundle = {
|
||||
let mut builder = Builder::new(
|
||||
Flags::from_parts(true, true),
|
||||
Flags::from_parts(true, true, false),
|
||||
Anchor::from_bytes([0; 32]).unwrap(),
|
||||
);
|
||||
// The builder pads to two actions, and shuffles their order. Add two recipients
|
||||
|
|
|
@ -947,7 +947,7 @@ pub mod testing {
|
|||
/// Create a bundle from the set of arbitrary bundle inputs.
|
||||
fn into_bundle<V: TryFrom<i64> + Copy + Into<i64>>(mut self) -> Bundle<Authorized, V> {
|
||||
let fvk = FullViewingKey::from(&self.sk);
|
||||
let flags = Flags::from_parts(true, true);
|
||||
let flags = Flags::from_parts(true, true, true);
|
||||
let mut builder = Builder::new(flags, self.anchor);
|
||||
|
||||
for (note, path) in self.notes.into_iter() {
|
||||
|
@ -1068,7 +1068,7 @@ mod tests {
|
|||
let recipient = fvk.address_at(0u32, Scope::External);
|
||||
|
||||
let mut builder = Builder::new(
|
||||
Flags::from_parts(true, true),
|
||||
Flags::from_parts(true, true, false),
|
||||
EMPTY_ROOTS[MERKLE_DEPTH_ORCHARD].into(),
|
||||
);
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ impl<T> Action<T> {
|
|||
cmx: *self.cmx(),
|
||||
enable_spend: flags.spends_enabled,
|
||||
enable_output: flags.outputs_enabled,
|
||||
enable_zsa: flags.zsa_enabled,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -57,18 +58,25 @@ pub struct Flags {
|
|||
/// guaranteed to be dummy notes. If `true`, the created notes may be either real or
|
||||
/// dummy notes.
|
||||
outputs_enabled: bool,
|
||||
/// Flag denoting whether ZSA transaction is enabled.
|
||||
///
|
||||
/// If `false`, all notes within [`Action`]s in the transaction's [`Bundle`] are
|
||||
/// guaranteed to be notes with native asset.
|
||||
zsa_enabled: bool,
|
||||
}
|
||||
|
||||
const FLAG_SPENDS_ENABLED: u8 = 0b0000_0001;
|
||||
const FLAG_OUTPUTS_ENABLED: u8 = 0b0000_0010;
|
||||
const FLAGS_EXPECTED_UNSET: u8 = !(FLAG_SPENDS_ENABLED | FLAG_OUTPUTS_ENABLED);
|
||||
const FLAG_ZSA_ENABLED: u8 = 0b0000_0100;
|
||||
const FLAGS_EXPECTED_UNSET: u8 = !(FLAG_SPENDS_ENABLED | FLAG_OUTPUTS_ENABLED | FLAG_ZSA_ENABLED);
|
||||
|
||||
impl Flags {
|
||||
/// Construct a set of flags from its constituent parts
|
||||
pub fn from_parts(spends_enabled: bool, outputs_enabled: bool) -> Self {
|
||||
pub fn from_parts(spends_enabled: bool, outputs_enabled: bool, zsa_enabled: bool) -> Self {
|
||||
Flags {
|
||||
spends_enabled,
|
||||
outputs_enabled,
|
||||
zsa_enabled,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,6 +98,14 @@ impl Flags {
|
|||
self.outputs_enabled
|
||||
}
|
||||
|
||||
/// Flag denoting whether ZSA transaction is enabled.
|
||||
///
|
||||
/// If `false`, all notes within [`Action`]s in the transaction's [`Bundle`] are
|
||||
/// guaranteed to be notes with native asset.
|
||||
pub fn zsa_enabled(&self) -> bool {
|
||||
self.zsa_enabled
|
||||
}
|
||||
|
||||
/// Serialize flags to a byte as defined in [Zcash Protocol Spec § 7.1: Transaction
|
||||
/// Encoding And Consensus][txencoding].
|
||||
///
|
||||
|
@ -102,6 +118,9 @@ impl Flags {
|
|||
if self.outputs_enabled {
|
||||
value |= FLAG_OUTPUTS_ENABLED;
|
||||
}
|
||||
if self.zsa_enabled {
|
||||
value |= FLAG_ZSA_ENABLED;
|
||||
}
|
||||
value
|
||||
}
|
||||
|
||||
|
@ -116,6 +135,7 @@ impl Flags {
|
|||
Some(Self::from_parts(
|
||||
value & FLAG_SPENDS_ENABLED != 0,
|
||||
value & FLAG_OUTPUTS_ENABLED != 0,
|
||||
value & FLAG_ZSA_ENABLED != 0,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
|
@ -607,8 +627,8 @@ pub mod testing {
|
|||
|
||||
prop_compose! {
|
||||
/// Create an arbitrary set of flags.
|
||||
pub fn arb_flags()(spends_enabled in prop::bool::ANY, outputs_enabled in prop::bool::ANY) -> Flags {
|
||||
Flags::from_parts(spends_enabled, outputs_enabled)
|
||||
pub fn arb_flags()(spends_enabled in prop::bool::ANY, outputs_enabled in prop::bool::ANY, zsa_enabled in prop::bool::ANY) -> Flags {
|
||||
Flags::from_parts(spends_enabled, outputs_enabled, zsa_enabled)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ use self::{
|
|||
};
|
||||
use crate::{
|
||||
builder::SpendInfo,
|
||||
bundle::Flags,
|
||||
circuit::gadget::mux_chip::{MuxChip, MuxConfig},
|
||||
constants::{
|
||||
OrchardCommitDomains, OrchardFixedBases, OrchardFixedBasesFull, OrchardHashDomains,
|
||||
|
@ -79,6 +80,7 @@ const RK_Y: usize = 5;
|
|||
const CMX: usize = 6;
|
||||
const ENABLE_SPEND: usize = 7;
|
||||
const ENABLE_OUTPUT: usize = 8;
|
||||
const ENABLE_ZSA: usize = 9;
|
||||
|
||||
/// Configuration needed to use the Orchard Action circuit.
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -231,6 +233,7 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
|||
// 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
|
||||
let q_orchard = meta.selector();
|
||||
meta.create_gate("Orchard circuit checks", |meta| {
|
||||
let q_orchard = meta.query_selector(q_orchard);
|
||||
|
@ -267,6 +270,8 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
|||
let psi_old = meta.query_advice(advices[4], Rotation::next());
|
||||
let psi_nf = meta.query_advice(advices[5], Rotation::next());
|
||||
|
||||
let enable_zsa = meta.query_advice(advices[6], Rotation::next());
|
||||
|
||||
Constraints::with_selector(
|
||||
q_orchard,
|
||||
[
|
||||
|
@ -318,11 +323,15 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
|||
),
|
||||
(
|
||||
"(split_flag = 0) => (psi_old = psi_nf)",
|
||||
(one - split_flag.clone()) * (psi_old - psi_nf),
|
||||
(one.clone() - split_flag.clone()) * (psi_old - psi_nf),
|
||||
),
|
||||
(
|
||||
"(split_flag = 1) => (is_native_asset = 0)",
|
||||
split_flag * is_native_asset,
|
||||
split_flag * is_native_asset.clone(),
|
||||
),
|
||||
(
|
||||
"(enable_zsa = 0) => (is_native_asset = 1)",
|
||||
(one.clone() - enable_zsa) * (one - is_native_asset),
|
||||
),
|
||||
],
|
||||
)
|
||||
|
@ -942,6 +951,14 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
|||
psi_old.copy_advice(|| "psi_old", &mut region, config.advices[4], 1)?;
|
||||
psi_nf.copy_advice(|| "psi_nf", &mut region, config.advices[5], 1)?;
|
||||
|
||||
region.assign_advice_from_instance(
|
||||
|| "enable zsa",
|
||||
config.primary,
|
||||
ENABLE_ZSA,
|
||||
config.advices[6],
|
||||
1,
|
||||
)?;
|
||||
|
||||
config.q_orchard.enable(&mut region, 0)
|
||||
},
|
||||
)?;
|
||||
|
@ -999,6 +1016,7 @@ pub struct Instance {
|
|||
pub(crate) cmx: ExtractedNoteCommitment,
|
||||
pub(crate) enable_spend: bool,
|
||||
pub(crate) enable_output: bool,
|
||||
pub(crate) enable_zsa: bool,
|
||||
}
|
||||
|
||||
impl Instance {
|
||||
|
@ -1015,8 +1033,7 @@ impl Instance {
|
|||
nf_old: Nullifier,
|
||||
rk: VerificationKey<SpendAuth>,
|
||||
cmx: ExtractedNoteCommitment,
|
||||
enable_spend: bool,
|
||||
enable_output: bool,
|
||||
flags: Flags,
|
||||
) -> Self {
|
||||
Instance {
|
||||
anchor,
|
||||
|
@ -1024,13 +1041,14 @@ impl Instance {
|
|||
nf_old,
|
||||
rk,
|
||||
cmx,
|
||||
enable_spend,
|
||||
enable_output,
|
||||
enable_spend: flags.spends_enabled(),
|
||||
enable_output: flags.outputs_enabled(),
|
||||
enable_zsa: flags.zsa_enabled(),
|
||||
}
|
||||
}
|
||||
|
||||
fn to_halo2_instance(&self) -> [[vesta::Scalar; 9]; 1] {
|
||||
let mut instance = [vesta::Scalar::zero(); 9];
|
||||
fn to_halo2_instance(&self) -> [[vesta::Scalar; 10]; 1] {
|
||||
let mut instance = [vesta::Scalar::zero(); 10];
|
||||
|
||||
instance[ANCHOR] = self.anchor.inner();
|
||||
instance[CV_NET_X] = self.cv_net.x();
|
||||
|
@ -1048,6 +1066,7 @@ impl Instance {
|
|||
instance[CMX] = self.cmx.inner();
|
||||
instance[ENABLE_SPEND] = vesta::Scalar::from(u64::from(self.enable_spend));
|
||||
instance[ENABLE_OUTPUT] = vesta::Scalar::from(u64::from(self.enable_output));
|
||||
instance[ENABLE_ZSA] = vesta::Scalar::from(u64::from(self.enable_zsa));
|
||||
|
||||
[instance]
|
||||
}
|
||||
|
@ -1167,6 +1186,7 @@ mod tests {
|
|||
|
||||
use super::{Circuit, Instance, Proof, ProvingKey, VerifyingKey, K};
|
||||
use crate::builder::SpendInfo;
|
||||
use crate::bundle::Flags;
|
||||
use crate::note::commitment::NoteCommitTrapdoor;
|
||||
use crate::note::{AssetBase, Nullifier};
|
||||
use crate::primitives::redpallas::VerificationKey;
|
||||
|
@ -1234,6 +1254,7 @@ mod tests {
|
|||
cmx,
|
||||
enable_spend: true,
|
||||
enable_output: true,
|
||||
enable_zsa: false,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
@ -1314,6 +1335,7 @@ mod tests {
|
|||
w.write_all(&[
|
||||
if instance.enable_spend { 1 } else { 0 },
|
||||
if instance.enable_output { 1 } else { 0 },
|
||||
if instance.enable_zsa { 1 } else { 0 },
|
||||
])?;
|
||||
|
||||
w.write_all(proof.as_ref())?;
|
||||
|
@ -1344,8 +1366,15 @@ mod tests {
|
|||
crate::note::ExtractedNoteCommitment::from_bytes(&read_32_bytes(&mut r)).unwrap();
|
||||
let enable_spend = read_bool(&mut r);
|
||||
let enable_output = read_bool(&mut r);
|
||||
let instance =
|
||||
Instance::from_parts(anchor, cv_net, nf_old, rk, cmx, enable_spend, enable_output);
|
||||
let enable_zsa = read_bool(&mut r);
|
||||
let instance = Instance::from_parts(
|
||||
anchor,
|
||||
cv_net,
|
||||
nf_old,
|
||||
rk,
|
||||
cmx,
|
||||
Flags::from_parts(enable_spend, enable_output, enable_zsa),
|
||||
);
|
||||
|
||||
let mut proof_bytes = vec![];
|
||||
r.read_to_end(&mut proof_bytes)?;
|
||||
|
@ -1533,6 +1562,7 @@ mod tests {
|
|||
cmx,
|
||||
enable_spend: true,
|
||||
enable_output: true,
|
||||
enable_zsa: true,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
@ -1573,6 +1603,7 @@ mod tests {
|
|||
cmx: instance.cmx,
|
||||
enable_spend: instance.enable_spend,
|
||||
enable_output: instance.enable_output,
|
||||
enable_zsa: instance.enable_zsa,
|
||||
};
|
||||
check_proof_of_orchard_circuit(&circuit, &instance_wrong_cv_net, false);
|
||||
|
||||
|
@ -1586,6 +1617,7 @@ mod tests {
|
|||
cmx: instance.cmx,
|
||||
enable_spend: instance.enable_spend,
|
||||
enable_output: instance.enable_output,
|
||||
enable_zsa: instance.enable_zsa,
|
||||
};
|
||||
check_proof_of_orchard_circuit(&circuit, &instance_wrong_rk, false);
|
||||
|
||||
|
@ -1627,6 +1659,7 @@ mod tests {
|
|||
cmx: random_note_commitment(&mut rng).into(),
|
||||
enable_spend: instance.enable_spend,
|
||||
enable_output: instance.enable_output,
|
||||
enable_zsa: instance.enable_zsa,
|
||||
};
|
||||
check_proof_of_orchard_circuit(&circuit, &instance_wrong_cmx_pub, false);
|
||||
|
||||
|
@ -1640,6 +1673,7 @@ mod tests {
|
|||
cmx: instance.cmx,
|
||||
enable_spend: instance.enable_spend,
|
||||
enable_output: instance.enable_output,
|
||||
enable_zsa: instance.enable_zsa,
|
||||
};
|
||||
check_proof_of_orchard_circuit(&circuit, &instance_wrong_nf_old_pub, false);
|
||||
|
||||
|
@ -1672,6 +1706,22 @@ mod tests {
|
|||
};
|
||||
check_proof_of_orchard_circuit(&circuit_wrong_psi_nf, &instance, false);
|
||||
}
|
||||
|
||||
// If asset is not equal to the native asset, set enable_zsa = 0
|
||||
// The proof should fail
|
||||
if !is_native_asset {
|
||||
let instance_wrong_enable_zsa = Instance {
|
||||
anchor: instance.anchor,
|
||||
cv_net: instance.cv_net.clone(),
|
||||
nf_old: instance.nf_old,
|
||||
rk: instance.rk.clone(),
|
||||
cmx: instance.cmx,
|
||||
enable_spend: instance.enable_spend,
|
||||
enable_output: instance.enable_output,
|
||||
enable_zsa: false,
|
||||
};
|
||||
check_proof_of_orchard_circuit(&circuit, &instance_wrong_enable_zsa, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
@ -62,7 +62,7 @@ fn bundle_chain() {
|
|||
// Use the empty tree.
|
||||
let anchor = MerkleHashOrchard::empty_root(32.into()).into();
|
||||
|
||||
let mut builder = Builder::new(Flags::from_parts(false, true), anchor);
|
||||
let mut builder = Builder::new(Flags::from_parts(false, true, false), anchor);
|
||||
assert_eq!(
|
||||
builder.add_recipient(
|
||||
None,
|
||||
|
@ -96,7 +96,7 @@ fn bundle_chain() {
|
|||
|
||||
let (merkle_path, anchor) = build_merkle_path(¬e);
|
||||
|
||||
let mut builder = Builder::new(Flags::from_parts(true, true), anchor);
|
||||
let mut builder = Builder::new(Flags::from_parts(true, true, false), anchor);
|
||||
assert_eq!(builder.add_spend(fvk, note, merkle_path), Ok(()));
|
||||
assert_eq!(
|
||||
builder.add_recipient(
|
||||
|
|
|
@ -189,7 +189,7 @@ fn create_native_note(keys: &Keychain) -> Note {
|
|||
// Use the empty tree.
|
||||
let anchor = MerkleHashOrchard::empty_root(32.into()).into();
|
||||
|
||||
let mut builder = Builder::new(Flags::from_parts(false, true), anchor);
|
||||
let mut builder = Builder::new(Flags::from_parts(false, true, false), anchor);
|
||||
assert_eq!(
|
||||
builder.add_recipient(
|
||||
None,
|
||||
|
@ -244,7 +244,7 @@ fn build_and_verify_bundle(
|
|||
) -> Result<(), String> {
|
||||
let rng = OsRng;
|
||||
let shielded_bundle: Bundle<_, i64> = {
|
||||
let mut builder = Builder::new(Flags::from_parts(true, true), anchor);
|
||||
let mut builder = Builder::new(Flags::from_parts(true, true, true), anchor);
|
||||
|
||||
spends
|
||||
.iter()
|
||||
|
|
Loading…
Reference in New Issue