mirror of https://github.com/zcash/orchard.git
Merge branch 'zsa1' into zsa-builder
This commit is contained in:
commit
60a17a2179
11
CHANGELOG.md
11
CHANGELOG.md
|
@ -7,6 +7,17 @@ and this project adheres to Rust's notion of
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [0.2.0] - 2022-06-24
|
||||||
|
### Added
|
||||||
|
- `orchard::bundle::BatchValidator`
|
||||||
|
- `orchard::note_encryption`:
|
||||||
|
- `CompactAction::from_parts`
|
||||||
|
- `CompactAction::nullifier`
|
||||||
|
- `OrchardDomain::for_nullifier`
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Migrated to `halo2_proofs 0.2`.
|
||||||
|
|
||||||
## [0.1.0] - 2022-05-10
|
## [0.1.0] - 2022-05-10
|
||||||
### Changed
|
### Changed
|
||||||
- Migrated to `bitvec 1`, `ff 0.12`, `group 0.12`, `incrementalmerkletree 0.3`,
|
- Migrated to `bitvec 1`, `ff 0.12`, `group 0.12`, `incrementalmerkletree 0.3`,
|
||||||
|
|
13
Cargo.toml
13
Cargo.toml
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "orchard"
|
name = "orchard"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
authors = [
|
authors = [
|
||||||
"Sean Bowe <sean@electriccoin.co>",
|
"Sean Bowe <sean@electriccoin.co>",
|
||||||
"Jack Grigg <jack@electriccoin.co>",
|
"Jack Grigg <jack@electriccoin.co>",
|
||||||
|
@ -29,8 +29,8 @@ blake2b_simd = "1"
|
||||||
ff = "0.12"
|
ff = "0.12"
|
||||||
fpe = "0.5"
|
fpe = "0.5"
|
||||||
group = "0.12"
|
group = "0.12"
|
||||||
halo2_gadgets = "0.1"
|
halo2_gadgets = "0.2"
|
||||||
halo2_proofs = "0.1"
|
halo2_proofs = "0.2"
|
||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
lazy_static = "1"
|
lazy_static = "1"
|
||||||
memuse = { version = "0.2", features = ["nonempty"] }
|
memuse = { version = "0.2", features = ["nonempty"] }
|
||||||
|
@ -44,18 +44,21 @@ subtle = "2.3"
|
||||||
zcash_note_encryption = "0.1"
|
zcash_note_encryption = "0.1"
|
||||||
incrementalmerkletree = "0.3"
|
incrementalmerkletree = "0.3"
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
tracing = "0.1"
|
||||||
|
|
||||||
# Developer tooling dependencies
|
# Developer tooling dependencies
|
||||||
plotters = { version = "0.3.0", optional = true }
|
plotters = { version = "0.3.0", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
criterion = "0.3"
|
criterion = "0.3"
|
||||||
halo2_gadgets = { version = "0.1", features = ["test-dependencies"] }
|
halo2_gadgets = { version = "0.2", features = ["test-dependencies"] }
|
||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
proptest = "1.0.0"
|
proptest = "1.0.0"
|
||||||
zcash_note_encryption = { version = "0.1", features = ["pre-zip-212"] }
|
zcash_note_encryption = { version = "0.1", features = ["pre-zip-212"] }
|
||||||
|
|
||||||
[target.'cfg(unix)'.dev-dependencies]
|
[target.'cfg(unix)'.dev-dependencies]
|
||||||
pprof = { version = "0.8", features = ["criterion", "flamegraph"] } # MSRV 1.56
|
pprof = { version = "0.9", features = ["criterion", "flamegraph"] } # MSRV 1.56
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
bench = false
|
bench = false
|
||||||
|
|
|
@ -161,8 +161,8 @@ of such entity.
|
||||||
restricted or conditioned by this License or by law, and Licensor promises not
|
restricted or conditioned by this License or by law, and Licensor promises not
|
||||||
to interfere with or be responsible for such uses by You.
|
to interfere with or be responsible for such uses by You.
|
||||||
|
|
||||||
16. **Modification of This License.** This License is Copyright © 2007 Zooko
|
16. **Modification of This License.** This License is Copyright © 2021-2022 Electric Coin Company.
|
||||||
Wilcox-O'Hearn. Permission is granted to copy, distribute, or communicate this
|
Permission is granted to copy, distribute, or communicate this
|
||||||
License without modification. Nothing in this License permits You to modify
|
License without modification. Nothing in this License permits You to modify
|
||||||
this License as applied to the Original Work or to Derivative Works. However,
|
this License as applied to the Original Work or to Derivative Works. However,
|
||||||
You may modify the text of this License and copy, distribute or communicate
|
You may modify the text of this License and copy, distribute or communicate
|
||||||
|
|
|
@ -246,7 +246,8 @@ The $\mathit{Commit}^{\mathsf{nf}}$ variants were considered to avoid directly d
|
||||||
$\mathsf{cm}$ (which in its native type is a base field element, not a group element). We
|
$\mathsf{cm}$ (which in its native type is a base field element, not a group element). We
|
||||||
decided instead to follow Sapling by defining an intermediate representation of
|
decided instead to follow Sapling by defining an intermediate representation of
|
||||||
$\mathsf{cm}$ as a group element, that is only used in nullifier computation. The circuit
|
$\mathsf{cm}$ as a group element, that is only used in nullifier computation. The circuit
|
||||||
already needs to compute $\mathsf{cm}$, so this improves performance by removing
|
already needs to compute $\mathsf{cm}$, so this improves performance by removing an
|
||||||
|
additional commitment calculation from the circuit.
|
||||||
|
|
||||||
We also considered variants that used a choice of fixed bases $\mathcal{G_v}$ to provide
|
We also considered variants that used a choice of fixed bases $\mathcal{G_v}$ to provide
|
||||||
domain separation for zero-valued notes. The most performant design (similar to the chosen
|
domain separation for zero-valued notes. The most performant design (similar to the chosen
|
||||||
|
|
|
@ -5,6 +5,7 @@ use core::iter;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use ff::Field;
|
use ff::Field;
|
||||||
|
use halo2_proofs::circuit::Value;
|
||||||
use nonempty::NonEmpty;
|
use nonempty::NonEmpty;
|
||||||
use pasta_curves::pallas;
|
use pasta_curves::pallas;
|
||||||
use rand::{prelude::SliceRandom, CryptoRng, RngCore};
|
use rand::{prelude::SliceRandom, CryptoRng, RngCore};
|
||||||
|
@ -181,6 +182,7 @@ impl ActionInfo {
|
||||||
let ak: SpendValidatingKey = self.spend.fvk.clone().into();
|
let ak: SpendValidatingKey = self.spend.fvk.clone().into();
|
||||||
let alpha = pallas::Scalar::random(&mut rng);
|
let alpha = pallas::Scalar::random(&mut rng);
|
||||||
let rk = ak.randomize(&alpha);
|
let rk = ak.randomize(&alpha);
|
||||||
|
let note_type = self.spend.note.note_type();
|
||||||
|
|
||||||
let note = Note::new(
|
let note = Note::new(
|
||||||
self.output.recipient,
|
self.output.recipient,
|
||||||
|
@ -225,26 +227,25 @@ impl ActionInfo {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
Circuit {
|
Circuit {
|
||||||
path: Some(self.spend.merkle_path.auth_path()),
|
path: Value::known(self.spend.merkle_path.auth_path()),
|
||||||
pos: Some(self.spend.merkle_path.position()),
|
pos: Value::known(self.spend.merkle_path.position()),
|
||||||
g_d_old: Some(sender_address.g_d()),
|
g_d_old: Value::known(sender_address.g_d()),
|
||||||
pk_d_old: Some(*sender_address.pk_d()),
|
pk_d_old: Value::known(*sender_address.pk_d()),
|
||||||
v_old: Some(self.spend.note.value()),
|
v_old: Value::known(self.spend.note.value()),
|
||||||
//split: Some(self.spend.split_flag),
|
rho_old: Value::known(rho_old),
|
||||||
rho_old: Some(rho_old),
|
psi_old: Value::known(psi_old),
|
||||||
psi_old: Some(psi_old),
|
rcm_old: Value::known(rcm_old),
|
||||||
rcm_old: Some(rcm_old),
|
cm_old: Value::known(self.spend.note.commitment()),
|
||||||
cm_old: Some(self.spend.note.commitment()),
|
alpha: Value::known(alpha),
|
||||||
alpha: Some(alpha),
|
ak: Value::known(ak),
|
||||||
ak: Some(ak),
|
nk: Value::known(*self.spend.fvk.nk()),
|
||||||
nk: Some(*self.spend.fvk.nk()),
|
rivk: Value::known(self.spend.fvk.rivk(self.spend.scope)),
|
||||||
rivk: Some(self.spend.fvk.rivk(self.spend.scope)),
|
g_d_new: Value::known(note.recipient().g_d()),
|
||||||
g_d_new: Some(note.recipient().g_d()),
|
pk_d_new: Value::known(*note.recipient().pk_d()),
|
||||||
pk_d_new: Some(*note.recipient().pk_d()),
|
v_new: Value::known(note.value()),
|
||||||
v_new: Some(note.value()),
|
psi_new: Value::known(note.rseed().psi(¬e.rho())),
|
||||||
psi_new: Some(note.rseed().psi(¬e.rho())),
|
rcm_new: Value::known(note.rseed().rcm(¬e.rho())),
|
||||||
rcm_new: Some(note.rseed().rcm(¬e.rho())),
|
rcv: Value::known(self.rcv),
|
||||||
rcv: Some(self.rcv),
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -273,8 +274,16 @@ impl Builder {
|
||||||
|
|
||||||
/// Adds a note to be spent in this transaction.
|
/// Adds a note to be spent in this transaction.
|
||||||
///
|
///
|
||||||
|
/// - `note` is a spendable note, obtained by trial-decrypting an [`Action`] using the
|
||||||
|
/// [`zcash_note_encryption`] crate instantiated with [`OrchardDomain`].
|
||||||
|
/// - `merkle_path` can be obtained using the [`incrementalmerkletree`] crate
|
||||||
|
/// instantiated with [`MerkleHashOrchard`].
|
||||||
|
///
|
||||||
/// Returns an error if the given Merkle path does not have the required anchor for
|
/// Returns an error if the given Merkle path does not have the required anchor for
|
||||||
/// the given note.
|
/// the given note.
|
||||||
|
///
|
||||||
|
/// [`OrchardDomain`]: crate::note_encryption::OrchardDomain
|
||||||
|
/// [`MerkleHashOrchard`]: crate::tree::MerkleHashOrchard
|
||||||
pub fn add_spend(
|
pub fn add_spend(
|
||||||
&mut self,
|
&mut self,
|
||||||
fvk: FullViewingKey,
|
fvk: FullViewingKey,
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
//! Structs related to bundles of Orchard actions.
|
//! Structs related to bundles of Orchard actions.
|
||||||
|
|
||||||
|
mod batch;
|
||||||
pub mod commitments;
|
pub mod commitments;
|
||||||
|
|
||||||
|
pub use batch::BatchValidator;
|
||||||
|
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
use blake2b_simd::Hash as Blake2bHash;
|
use blake2b_simd::Hash as Blake2bHash;
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
use halo2_proofs::plonk;
|
||||||
|
use pasta_curves::vesta;
|
||||||
|
use rand::{CryptoRng, RngCore};
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
|
use super::{Authorized, Bundle};
|
||||||
|
use crate::{
|
||||||
|
circuit::VerifyingKey,
|
||||||
|
primitives::redpallas::{self, Binding, SpendAuth},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A signature within an authorized Orchard bundle.
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct BundleSignature {
|
||||||
|
/// The signature item for validation.
|
||||||
|
signature: redpallas::batch::Item<SpendAuth, Binding>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Batch validation context for Orchard.
|
||||||
|
///
|
||||||
|
/// This batch-validates proofs and RedPallas signatures.
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct BatchValidator {
|
||||||
|
proofs: plonk::BatchVerifier<vesta::Affine>,
|
||||||
|
signatures: Vec<BundleSignature>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BatchValidator {
|
||||||
|
/// Constructs a new batch validation context.
|
||||||
|
pub fn new() -> Self {
|
||||||
|
BatchValidator {
|
||||||
|
proofs: plonk::BatchVerifier::new(),
|
||||||
|
signatures: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds the proof and RedPallas signatures from the given bundle to the validator.
|
||||||
|
pub fn add_bundle<V: Copy + Into<i64>>(
|
||||||
|
&mut self,
|
||||||
|
bundle: &Bundle<Authorized, V>,
|
||||||
|
sighash: [u8; 32],
|
||||||
|
) {
|
||||||
|
for action in bundle.actions().iter() {
|
||||||
|
self.signatures.push(BundleSignature {
|
||||||
|
signature: action
|
||||||
|
.rk()
|
||||||
|
.create_batch_item(action.authorization().clone(), &sighash),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
self.signatures.push(BundleSignature {
|
||||||
|
signature: bundle
|
||||||
|
.binding_validating_key()
|
||||||
|
.create_batch_item(bundle.authorization().binding_signature().clone(), &sighash),
|
||||||
|
});
|
||||||
|
|
||||||
|
bundle
|
||||||
|
.authorization()
|
||||||
|
.proof()
|
||||||
|
.add_to_batch(&mut self.proofs, bundle.to_instances());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Batch-validates the accumulated bundles.
|
||||||
|
///
|
||||||
|
/// Returns `true` if every proof and signature in every bundle added to the batch
|
||||||
|
/// validator is valid, or `false` if one or more are invalid. No attempt is made to
|
||||||
|
/// figure out which of the accumulated bundles might be invalid; if that information
|
||||||
|
/// is desired, construct separate [`BatchValidator`]s for sub-batches of the bundles.
|
||||||
|
pub fn validate<R: RngCore + CryptoRng>(self, vk: &VerifyingKey, rng: R) -> bool {
|
||||||
|
if self.signatures.is_empty() {
|
||||||
|
// An empty batch is always valid, but is not free to run; skip it.
|
||||||
|
// Note that a transaction has at least a binding signature, so if
|
||||||
|
// there are no signatures, there are also no proofs.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut validator = redpallas::batch::Verifier::new();
|
||||||
|
for sig in self.signatures.iter() {
|
||||||
|
validator.queue(sig.signature.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
match validator.verify(rng) {
|
||||||
|
// If signatures are valid, check the proofs.
|
||||||
|
Ok(()) => self.proofs.finalize(&vk.params, &vk.vk),
|
||||||
|
Err(e) => {
|
||||||
|
debug!("RedPallas batch validation failed: {}", e);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
157
src/circuit.rs
157
src/circuit.rs
|
@ -4,10 +4,10 @@ use core::fmt;
|
||||||
|
|
||||||
use group::{Curve, GroupEncoding};
|
use group::{Curve, GroupEncoding};
|
||||||
use halo2_proofs::{
|
use halo2_proofs::{
|
||||||
circuit::{floor_planner, Layouter},
|
circuit::{floor_planner, Layouter, Value},
|
||||||
plonk::{
|
plonk::{
|
||||||
self, Advice, Column, Constraints, Expression, Instance as InstanceColumn, Selector,
|
self, Advice, BatchVerifier, Column, Constraints, Expression, Instance as InstanceColumn,
|
||||||
SingleVerifier,
|
Selector, SingleVerifier,
|
||||||
},
|
},
|
||||||
poly::Rotation,
|
poly::Rotation,
|
||||||
transcript::{Blake2bRead, Blake2bWrite},
|
transcript::{Blake2bRead, Blake2bWrite},
|
||||||
|
@ -99,26 +99,25 @@ pub struct Config {
|
||||||
/// The Orchard Action circuit.
|
/// The Orchard Action circuit.
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct Circuit {
|
pub struct Circuit {
|
||||||
pub(crate) path: Option<[MerkleHashOrchard; MERKLE_DEPTH_ORCHARD]>,
|
pub(crate) path: Value<[MerkleHashOrchard; MERKLE_DEPTH_ORCHARD]>,
|
||||||
pub(crate) pos: Option<u32>,
|
pub(crate) pos: Value<u32>,
|
||||||
pub(crate) g_d_old: Option<NonIdentityPallasPoint>,
|
pub(crate) g_d_old: Value<NonIdentityPallasPoint>,
|
||||||
pub(crate) pk_d_old: Option<DiversifiedTransmissionKey>,
|
pub(crate) pk_d_old: Value<DiversifiedTransmissionKey>,
|
||||||
pub(crate) v_old: Option<NoteValue>,
|
pub(crate) v_old: Value<NoteValue>,
|
||||||
// pub(crate) split: Option<bool>,
|
pub(crate) rho_old: Value<Nullifier>,
|
||||||
pub(crate) rho_old: Option<Nullifier>,
|
pub(crate) psi_old: Value<pallas::Base>,
|
||||||
pub(crate) psi_old: Option<pallas::Base>,
|
pub(crate) rcm_old: Value<NoteCommitTrapdoor>,
|
||||||
pub(crate) rcm_old: Option<NoteCommitTrapdoor>,
|
pub(crate) cm_old: Value<NoteCommitment>,
|
||||||
pub(crate) cm_old: Option<NoteCommitment>,
|
pub(crate) alpha: Value<pallas::Scalar>,
|
||||||
pub(crate) alpha: Option<pallas::Scalar>,
|
pub(crate) ak: Value<SpendValidatingKey>,
|
||||||
pub(crate) ak: Option<SpendValidatingKey>,
|
pub(crate) nk: Value<NullifierDerivingKey>,
|
||||||
pub(crate) nk: Option<NullifierDerivingKey>,
|
pub(crate) rivk: Value<CommitIvkRandomness>,
|
||||||
pub(crate) rivk: Option<CommitIvkRandomness>,
|
pub(crate) g_d_new: Value<NonIdentityPallasPoint>,
|
||||||
pub(crate) g_d_new: Option<NonIdentityPallasPoint>,
|
pub(crate) pk_d_new: Value<DiversifiedTransmissionKey>,
|
||||||
pub(crate) pk_d_new: Option<DiversifiedTransmissionKey>,
|
pub(crate) v_new: Value<NoteValue>,
|
||||||
pub(crate) v_new: Option<NoteValue>,
|
pub(crate) psi_new: Value<pallas::Base>,
|
||||||
pub(crate) psi_new: Option<pallas::Base>,
|
pub(crate) rcm_new: Value<NoteCommitTrapdoor>,
|
||||||
pub(crate) rcm_new: Option<NoteCommitTrapdoor>,
|
pub(crate) rcv: Value<ValueCommitTrapdoor>,
|
||||||
pub(crate) rcv: Option<ValueCommitTrapdoor>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl plonk::Circuit<pallas::Base> for Circuit {
|
impl plonk::Circuit<pallas::Base> for Circuit {
|
||||||
|
@ -359,7 +358,7 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Witness ak_P.
|
// Witness ak_P.
|
||||||
let ak_P: Option<pallas::Point> = self.ak.as_ref().map(|ak| ak.into());
|
let ak_P: Value<pallas::Point> = self.ak.as_ref().map(|ak| ak.into());
|
||||||
let ak_P = NonIdentityPoint::new(
|
let ak_P = NonIdentityPoint::new(
|
||||||
ecc_chip.clone(),
|
ecc_chip.clone(),
|
||||||
layouter.namespace(|| "witness ak_P"),
|
layouter.namespace(|| "witness ak_P"),
|
||||||
|
@ -409,8 +408,8 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
||||||
let v_net_magnitude_sign = {
|
let v_net_magnitude_sign = {
|
||||||
// Witness the magnitude and sign of v_net = v_old - v_new
|
// Witness the magnitude and sign of v_net = v_old - v_new
|
||||||
let v_net_magnitude_sign = {
|
let v_net_magnitude_sign = {
|
||||||
let magnitude_sign = self.v_old.zip(self.v_new).map(|(v_old, v_new)| {
|
let v_net = self.v_old - self.v_new;
|
||||||
let v_net = v_old - v_new;
|
let magnitude_sign = v_net.map(|v_net| {
|
||||||
let (magnitude, sign) = v_net.magnitude_sign();
|
let (magnitude, sign) = v_net.magnitude_sign();
|
||||||
|
|
||||||
(
|
(
|
||||||
|
@ -508,7 +507,7 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
||||||
let ak = ak_P.extract_p().inner().clone();
|
let ak = ak_P.extract_p().inner().clone();
|
||||||
let rivk = ScalarFixed::new(
|
let rivk = ScalarFixed::new(
|
||||||
ecc_chip.clone(),
|
ecc_chip.clone(),
|
||||||
layouter.namespace(|| "rcv"),
|
layouter.namespace(|| "rivk"),
|
||||||
self.rivk.map(|rivk| rivk.inner()),
|
self.rivk.map(|rivk| rivk.inner()),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
@ -610,7 +609,7 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
||||||
|
|
||||||
let rcm_new = ScalarFixed::new(
|
let rcm_new = ScalarFixed::new(
|
||||||
ecc_chip,
|
ecc_chip,
|
||||||
layouter.namespace(|| "rcm_old"),
|
layouter.namespace(|| "rcm_new"),
|
||||||
self.rcm_new.as_ref().map(|rcm_new| rcm_new.inner()),
|
self.rcm_new.as_ref().map(|rcm_new| rcm_new.inner()),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
@ -691,8 +690,8 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
||||||
/// The verifying key for the Orchard Action circuit.
|
/// The verifying key for the Orchard Action circuit.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct VerifyingKey {
|
pub struct VerifyingKey {
|
||||||
params: halo2_proofs::poly::commitment::Params<vesta::Affine>,
|
pub(crate) params: halo2_proofs::poly::commitment::Params<vesta::Affine>,
|
||||||
vk: plonk::VerifyingKey<vesta::Affine>,
|
pub(crate) vk: plonk::VerifyingKey<vesta::Affine>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VerifyingKey {
|
impl VerifyingKey {
|
||||||
|
@ -867,6 +866,24 @@ impl Proof {
|
||||||
plonk::verify_proof(&vk.params, &vk.vk, strategy, &instances, &mut transcript)
|
plonk::verify_proof(&vk.params, &vk.vk, strategy, &instances, &mut transcript)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn add_to_batch(
|
||||||
|
&self,
|
||||||
|
batch: &mut BatchVerifier<vesta::Affine>,
|
||||||
|
instances: Vec<Instance>,
|
||||||
|
) {
|
||||||
|
let instances = instances
|
||||||
|
.iter()
|
||||||
|
.map(|i| {
|
||||||
|
i.to_halo2_instance()
|
||||||
|
.into_iter()
|
||||||
|
.map(|c| c.into_iter().collect())
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
batch.add_proof(instances, self.0.clone());
|
||||||
|
}
|
||||||
|
|
||||||
/// Constructs a new Proof value.
|
/// Constructs a new Proof value.
|
||||||
pub fn new(bytes: Vec<u8>) -> Self {
|
pub fn new(bytes: Vec<u8>) -> Self {
|
||||||
Proof(bytes)
|
Proof(bytes)
|
||||||
|
@ -878,7 +895,7 @@ mod tests {
|
||||||
use core::iter;
|
use core::iter;
|
||||||
|
|
||||||
use ff::Field;
|
use ff::Field;
|
||||||
use halo2_proofs::dev::MockProver;
|
use halo2_proofs::{circuit::Value, dev::MockProver};
|
||||||
use pasta_curves::pallas;
|
use pasta_curves::pallas;
|
||||||
use rand::{rngs::OsRng, RngCore};
|
use rand::{rngs::OsRng, RngCore};
|
||||||
|
|
||||||
|
@ -914,26 +931,25 @@ mod tests {
|
||||||
|
|
||||||
(
|
(
|
||||||
Circuit {
|
Circuit {
|
||||||
path: Some(path.auth_path()),
|
path: Value::known(path.auth_path()),
|
||||||
pos: Some(path.position()),
|
pos: Value::known(path.position()),
|
||||||
g_d_old: Some(sender_address.g_d()),
|
g_d_old: Value::known(sender_address.g_d()),
|
||||||
pk_d_old: Some(*sender_address.pk_d()),
|
pk_d_old: Value::known(*sender_address.pk_d()),
|
||||||
v_old: Some(spent_note.value()),
|
v_old: Value::known(spent_note.value()),
|
||||||
// split: Some(false),
|
rho_old: Value::known(spent_note.rho()),
|
||||||
rho_old: Some(spent_note.rho()),
|
psi_old: Value::known(spent_note.rseed().psi(&spent_note.rho())),
|
||||||
psi_old: Some(spent_note.rseed().psi(&spent_note.rho())),
|
rcm_old: Value::known(spent_note.rseed().rcm(&spent_note.rho())),
|
||||||
rcm_old: Some(spent_note.rseed().rcm(&spent_note.rho())),
|
cm_old: Value::known(spent_note.commitment()),
|
||||||
cm_old: Some(spent_note.commitment()),
|
alpha: Value::known(alpha),
|
||||||
alpha: Some(alpha),
|
ak: Value::known(ak),
|
||||||
ak: Some(ak),
|
nk: Value::known(nk),
|
||||||
nk: Some(nk),
|
rivk: Value::known(rivk),
|
||||||
rivk: Some(rivk),
|
g_d_new: Value::known(output_note.recipient().g_d()),
|
||||||
g_d_new: Some(output_note.recipient().g_d()),
|
pk_d_new: Value::known(*output_note.recipient().pk_d()),
|
||||||
pk_d_new: Some(*output_note.recipient().pk_d()),
|
v_new: Value::known(output_note.value()),
|
||||||
v_new: Some(output_note.value()),
|
psi_new: Value::known(output_note.rseed().psi(&output_note.rho())),
|
||||||
psi_new: Some(output_note.rseed().psi(&output_note.rho())),
|
rcm_new: Value::known(output_note.rseed().rcm(&output_note.rho())),
|
||||||
rcm_new: Some(output_note.rseed().rcm(&output_note.rho())),
|
rcv: Value::known(rcv),
|
||||||
rcv: Some(rcv),
|
|
||||||
},
|
},
|
||||||
Instance {
|
Instance {
|
||||||
anchor,
|
anchor,
|
||||||
|
@ -1101,26 +1117,25 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let circuit = Circuit {
|
let circuit = Circuit {
|
||||||
path: None,
|
path: Value::unknown(),
|
||||||
pos: None,
|
pos: Value::unknown(),
|
||||||
g_d_old: None,
|
g_d_old: Value::unknown(),
|
||||||
pk_d_old: None,
|
pk_d_old: Value::unknown(),
|
||||||
v_old: None,
|
v_old: Value::unknown(),
|
||||||
rho_old: None,
|
rho_old: Value::unknown(),
|
||||||
psi_old: None,
|
psi_old: Value::unknown(),
|
||||||
rcm_old: None,
|
rcm_old: Value::unknown(),
|
||||||
cm_old: None,
|
cm_old: Value::unknown(),
|
||||||
alpha: None,
|
alpha: Value::unknown(),
|
||||||
ak: None,
|
ak: Value::unknown(),
|
||||||
nk: None,
|
nk: Value::unknown(),
|
||||||
rivk: None,
|
rivk: Value::unknown(),
|
||||||
g_d_new: None,
|
g_d_new: Value::unknown(),
|
||||||
pk_d_new: None,
|
pk_d_new: Value::unknown(),
|
||||||
v_new: None,
|
v_new: Value::unknown(),
|
||||||
psi_new: None,
|
psi_new: Value::unknown(),
|
||||||
rcm_new: None,
|
rcm_new: Value::unknown(),
|
||||||
rcv: None,
|
rcv: Value::unknown(),
|
||||||
// split: None,
|
|
||||||
};
|
};
|
||||||
halo2_proofs::dev::CircuitLayout::default()
|
halo2_proofs::dev::CircuitLayout::default()
|
||||||
.show_labels(false)
|
.show_labels(false)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use core::iter;
|
use core::iter;
|
||||||
|
|
||||||
use halo2_proofs::{
|
use halo2_proofs::{
|
||||||
circuit::{AssignedCell, Layouter},
|
circuit::{AssignedCell, Layouter, Value},
|
||||||
plonk::{Advice, Column, ConstraintSystem, Constraints, Error, Expression, Selector},
|
plonk::{Advice, Column, ConstraintSystem, Constraints, Error, Expression, Selector},
|
||||||
poly::Rotation,
|
poly::Rotation,
|
||||||
};
|
};
|
||||||
|
@ -417,11 +417,11 @@ pub(in crate::circuit) mod gadgets {
|
||||||
// Decompose the low 130 bits of a_prime = a + 2^130 - t_P, and output
|
// Decompose the low 130 bits of a_prime = a + 2^130 - t_P, and output
|
||||||
// the running sum at the end of it. If a_prime < 2^130, the running sum
|
// the running sum at the end of it. If a_prime < 2^130, the running sum
|
||||||
// will be 0.
|
// will be 0.
|
||||||
let a_prime = a.value().map(|a| {
|
let a_prime = {
|
||||||
let two_pow_130 = pallas::Base::from_u128(1u128 << 65).square();
|
let two_pow_130 = Value::known(pallas::Base::from_u128(1u128 << 65).square());
|
||||||
let t_p = pallas::Base::from_u128(T_P);
|
let t_p = Value::known(pallas::Base::from_u128(T_P));
|
||||||
a + two_pow_130 - t_p
|
a.value() + two_pow_130 - t_p
|
||||||
});
|
};
|
||||||
let zs = lookup_config.witness_check(
|
let zs = lookup_config.witness_check(
|
||||||
layouter.namespace(|| "Decompose low 130 bits of (a + 2^130 - t_P)"),
|
layouter.namespace(|| "Decompose low 130 bits of (a + 2^130 - t_P)"),
|
||||||
a_prime,
|
a_prime,
|
||||||
|
@ -461,12 +461,12 @@ pub(in crate::circuit) mod gadgets {
|
||||||
|
|
||||||
// Decompose the low 140 bits of b2_c_prime = b_2 + c * 2^5 + 2^140 - t_P, and output
|
// Decompose the low 140 bits of b2_c_prime = b_2 + c * 2^5 + 2^140 - t_P, and output
|
||||||
// the running sum at the end of it. If b2_c_prime < 2^140, the running sum will be 0.
|
// the running sum at the end of it. If b2_c_prime < 2^140, the running sum will be 0.
|
||||||
let b2_c_prime = b_2.inner().value().zip(c.value()).map(|(b_2, c)| {
|
let b2_c_prime = {
|
||||||
let two_pow_5 = pallas::Base::from(1 << 5);
|
let two_pow_5 = Value::known(pallas::Base::from(1 << 5));
|
||||||
let two_pow_140 = pallas::Base::from_u128(1u128 << 70).square();
|
let two_pow_140 = Value::known(pallas::Base::from_u128(1u128 << 70).square());
|
||||||
let t_p = pallas::Base::from_u128(T_P);
|
let t_p = Value::known(pallas::Base::from_u128(T_P));
|
||||||
b_2 + c * two_pow_5 + two_pow_140 - t_p
|
b_2.inner().value() + c.value() * two_pow_5 + two_pow_140 - t_p
|
||||||
});
|
};
|
||||||
let zs = lookup_config.witness_check(
|
let zs = lookup_config.witness_check(
|
||||||
layouter.namespace(|| "Decompose low 140 bits of (b_2 + c * 2^5 + 2^140 - t_P)"),
|
layouter.namespace(|| "Decompose low 140 bits of (b_2 + c * 2^5 + 2^140 - t_P)"),
|
||||||
b2_c_prime,
|
b2_c_prime,
|
||||||
|
@ -535,7 +535,7 @@ impl CommitIvkConfig {
|
||||||
|| "Witness b_1",
|
|| "Witness b_1",
|
||||||
self.advices[4],
|
self.advices[4],
|
||||||
offset,
|
offset,
|
||||||
|| gate_cells.b_1.inner().ok_or(Error::Synthesis),
|
|| *gate_cells.b_1.inner(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Copy in `b_2`
|
// Copy in `b_2`
|
||||||
|
@ -603,7 +603,7 @@ impl CommitIvkConfig {
|
||||||
|| "Witness d_1",
|
|| "Witness d_1",
|
||||||
self.advices[4],
|
self.advices[4],
|
||||||
offset,
|
offset,
|
||||||
|| gate_cells.d_1.inner().ok_or(Error::Synthesis),
|
|| *gate_cells.d_1.inner(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Copy in z13_c
|
// Copy in z13_c
|
||||||
|
@ -646,10 +646,10 @@ struct GateCells {
|
||||||
ak: AssignedCell<pallas::Base, pallas::Base>,
|
ak: AssignedCell<pallas::Base, pallas::Base>,
|
||||||
nk: AssignedCell<pallas::Base, pallas::Base>,
|
nk: AssignedCell<pallas::Base, pallas::Base>,
|
||||||
b_0: RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
b_0: RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
||||||
b_1: RangeConstrained<pallas::Base, Option<pallas::Base>>,
|
b_1: RangeConstrained<pallas::Base, Value<pallas::Base>>,
|
||||||
b_2: RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
b_2: RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
||||||
d_0: RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
d_0: RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
||||||
d_1: RangeConstrained<pallas::Base, Option<pallas::Base>>,
|
d_1: RangeConstrained<pallas::Base, Value<pallas::Base>>,
|
||||||
z13_a: AssignedCell<pallas::Base, pallas::Base>,
|
z13_a: AssignedCell<pallas::Base, pallas::Base>,
|
||||||
a_prime: AssignedCell<pallas::Base, pallas::Base>,
|
a_prime: AssignedCell<pallas::Base, pallas::Base>,
|
||||||
z13_a_prime: AssignedCell<pallas::Base, pallas::Base>,
|
z13_a_prime: AssignedCell<pallas::Base, pallas::Base>,
|
||||||
|
@ -680,7 +680,7 @@ mod tests {
|
||||||
utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions},
|
utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions},
|
||||||
};
|
};
|
||||||
use halo2_proofs::{
|
use halo2_proofs::{
|
||||||
circuit::{AssignedCell, Layouter, SimpleFloorPlanner},
|
circuit::{AssignedCell, Layouter, SimpleFloorPlanner, Value},
|
||||||
dev::MockProver,
|
dev::MockProver,
|
||||||
plonk::{Circuit, ConstraintSystem, Error},
|
plonk::{Circuit, ConstraintSystem, Error},
|
||||||
};
|
};
|
||||||
|
@ -691,8 +691,8 @@ mod tests {
|
||||||
fn commit_ivk() {
|
fn commit_ivk() {
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct MyCircuit {
|
struct MyCircuit {
|
||||||
ak: Option<pallas::Base>,
|
ak: Value<pallas::Base>,
|
||||||
nk: Option<pallas::Base>,
|
nk: Value<pallas::Base>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UtilitiesInstructions<pallas::Base> for MyCircuit {
|
impl UtilitiesInstructions<pallas::Base> for MyCircuit {
|
||||||
|
@ -809,8 +809,11 @@ mod tests {
|
||||||
|
|
||||||
// Use a random scalar for rivk
|
// Use a random scalar for rivk
|
||||||
let rivk = pallas::Scalar::random(OsRng);
|
let rivk = pallas::Scalar::random(OsRng);
|
||||||
let rivk_gadget =
|
let rivk_gadget = ScalarFixed::new(
|
||||||
ScalarFixed::new(ecc_chip.clone(), layouter.namespace(|| "rivk"), Some(rivk))?;
|
ecc_chip.clone(),
|
||||||
|
layouter.namespace(|| "rivk"),
|
||||||
|
Value::known(rivk),
|
||||||
|
)?;
|
||||||
|
|
||||||
let ivk = gadgets::commit_ivk(
|
let ivk = gadgets::commit_ivk(
|
||||||
sinsemilla_chip,
|
sinsemilla_chip,
|
||||||
|
@ -822,34 +825,29 @@ mod tests {
|
||||||
rivk_gadget,
|
rivk_gadget,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let expected_ivk = {
|
self.ak
|
||||||
let domain = CommitDomain::new(COMMIT_IVK_PERSONALIZATION);
|
.zip(self.nk)
|
||||||
// Hash ak || nk
|
.zip(ivk.inner().value())
|
||||||
domain
|
.assert_if_known(|((ak, nk), ivk)| {
|
||||||
.short_commit(
|
let expected_ivk = {
|
||||||
iter::empty()
|
let domain = CommitDomain::new(COMMIT_IVK_PERSONALIZATION);
|
||||||
.chain(
|
// Hash ak || nk
|
||||||
self.ak
|
domain
|
||||||
.unwrap()
|
.short_commit(
|
||||||
.to_le_bits()
|
iter::empty()
|
||||||
.iter()
|
.chain(
|
||||||
.by_vals()
|
ak.to_le_bits().iter().by_vals().take(L_ORCHARD_BASE),
|
||||||
.take(L_ORCHARD_BASE),
|
)
|
||||||
|
.chain(
|
||||||
|
nk.to_le_bits().iter().by_vals().take(L_ORCHARD_BASE),
|
||||||
|
),
|
||||||
|
&rivk,
|
||||||
)
|
)
|
||||||
.chain(
|
.unwrap()
|
||||||
self.nk
|
};
|
||||||
.unwrap()
|
|
||||||
.to_le_bits()
|
|
||||||
.iter()
|
|
||||||
.by_vals()
|
|
||||||
.take(L_ORCHARD_BASE),
|
|
||||||
),
|
|
||||||
&rivk,
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(&expected_ivk, ivk.inner().value().unwrap());
|
&&expected_ivk == ivk
|
||||||
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -860,38 +858,38 @@ mod tests {
|
||||||
let circuits = [
|
let circuits = [
|
||||||
// `ak` = 0, `nk` = 0
|
// `ak` = 0, `nk` = 0
|
||||||
MyCircuit {
|
MyCircuit {
|
||||||
ak: Some(pallas::Base::zero()),
|
ak: Value::known(pallas::Base::zero()),
|
||||||
nk: Some(pallas::Base::zero()),
|
nk: Value::known(pallas::Base::zero()),
|
||||||
},
|
},
|
||||||
// `ak` = T_Q - 1, `nk` = T_Q - 1
|
// `ak` = T_Q - 1, `nk` = T_Q - 1
|
||||||
MyCircuit {
|
MyCircuit {
|
||||||
ak: Some(pallas::Base::from_u128(T_Q - 1)),
|
ak: Value::known(pallas::Base::from_u128(T_Q - 1)),
|
||||||
nk: Some(pallas::Base::from_u128(T_Q - 1)),
|
nk: Value::known(pallas::Base::from_u128(T_Q - 1)),
|
||||||
},
|
},
|
||||||
// `ak` = T_Q, `nk` = T_Q
|
// `ak` = T_Q, `nk` = T_Q
|
||||||
MyCircuit {
|
MyCircuit {
|
||||||
ak: Some(pallas::Base::from_u128(T_Q)),
|
ak: Value::known(pallas::Base::from_u128(T_Q)),
|
||||||
nk: Some(pallas::Base::from_u128(T_Q)),
|
nk: Value::known(pallas::Base::from_u128(T_Q)),
|
||||||
},
|
},
|
||||||
// `ak` = 2^127 - 1, `nk` = 2^127 - 1
|
// `ak` = 2^127 - 1, `nk` = 2^127 - 1
|
||||||
MyCircuit {
|
MyCircuit {
|
||||||
ak: Some(pallas::Base::from_u128((1 << 127) - 1)),
|
ak: Value::known(pallas::Base::from_u128((1 << 127) - 1)),
|
||||||
nk: Some(pallas::Base::from_u128((1 << 127) - 1)),
|
nk: Value::known(pallas::Base::from_u128((1 << 127) - 1)),
|
||||||
},
|
},
|
||||||
// `ak` = 2^127, `nk` = 2^127
|
// `ak` = 2^127, `nk` = 2^127
|
||||||
MyCircuit {
|
MyCircuit {
|
||||||
ak: Some(pallas::Base::from_u128(1 << 127)),
|
ak: Value::known(pallas::Base::from_u128(1 << 127)),
|
||||||
nk: Some(pallas::Base::from_u128(1 << 127)),
|
nk: Value::known(pallas::Base::from_u128(1 << 127)),
|
||||||
},
|
},
|
||||||
// `ak` = 2^254 - 1, `nk` = 2^254 - 1
|
// `ak` = 2^254 - 1, `nk` = 2^254 - 1
|
||||||
MyCircuit {
|
MyCircuit {
|
||||||
ak: Some(two_pow_254 - pallas::Base::one()),
|
ak: Value::known(two_pow_254 - pallas::Base::one()),
|
||||||
nk: Some(two_pow_254 - pallas::Base::one()),
|
nk: Value::known(two_pow_254 - pallas::Base::one()),
|
||||||
},
|
},
|
||||||
// `ak` = 2^254, `nk` = 2^254
|
// `ak` = 2^254, `nk` = 2^254
|
||||||
MyCircuit {
|
MyCircuit {
|
||||||
ak: Some(two_pow_254),
|
ak: Value::known(two_pow_254),
|
||||||
nk: Some(two_pow_254),
|
nk: Value::known(two_pow_254),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ use halo2_gadgets::{
|
||||||
};
|
};
|
||||||
use halo2_proofs::{
|
use halo2_proofs::{
|
||||||
arithmetic::FieldExt,
|
arithmetic::FieldExt,
|
||||||
circuit::{AssignedCell, Chip, Layouter},
|
circuit::{AssignedCell, Chip, Layouter, Value},
|
||||||
plonk::{self, Advice, Assigned, Column},
|
plonk::{self, Advice, Assigned, Column},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -96,21 +96,14 @@ pub(in crate::circuit) trait AddInstruction<F: FieldExt>: Chip<F> {
|
||||||
pub(in crate::circuit) fn assign_free_advice<F: Field, V: Copy>(
|
pub(in crate::circuit) fn assign_free_advice<F: Field, V: Copy>(
|
||||||
mut layouter: impl Layouter<F>,
|
mut layouter: impl Layouter<F>,
|
||||||
column: Column<Advice>,
|
column: Column<Advice>,
|
||||||
value: Option<V>,
|
value: Value<V>,
|
||||||
) -> Result<AssignedCell<V, F>, plonk::Error>
|
) -> Result<AssignedCell<V, F>, plonk::Error>
|
||||||
where
|
where
|
||||||
for<'v> Assigned<F>: From<&'v V>,
|
for<'v> Assigned<F>: From<&'v V>,
|
||||||
{
|
{
|
||||||
layouter.assign_region(
|
layouter.assign_region(
|
||||||
|| "load private",
|
|| "load private",
|
||||||
|mut region| {
|
|mut region| region.assign_advice(|| "load private", column, 0, || value),
|
||||||
region.assign_advice(
|
|
||||||
|| "load private",
|
|
||||||
column,
|
|
||||||
0,
|
|
||||||
|| value.ok_or(plonk::Error::Synthesis),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,12 +74,7 @@ impl AddInstruction<pallas::Base> for AddChip {
|
||||||
b.copy_advice(|| "copy b", &mut region, self.config.b, 0)?;
|
b.copy_advice(|| "copy b", &mut region, self.config.b, 0)?;
|
||||||
|
|
||||||
let scalar_val = a.value().zip(b.value()).map(|(a, b)| a + b);
|
let scalar_val = a.value().zip(b.value()).map(|(a, b)| a + b);
|
||||||
region.assign_advice(
|
region.assign_advice(|| "c", self.config.c, 0, || scalar_val)
|
||||||
|| "c",
|
|
||||||
self.config.c,
|
|
||||||
0,
|
|
||||||
|| scalar_val.ok_or(plonk::Error::Synthesis),
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use core::iter;
|
use core::iter;
|
||||||
|
|
||||||
use halo2_proofs::{
|
use halo2_proofs::{
|
||||||
circuit::{AssignedCell, Layouter},
|
circuit::{AssignedCell, Layouter, Value},
|
||||||
plonk::{Advice, Column, ConstraintSystem, Constraints, Error, Expression, Selector},
|
plonk::{Advice, Column, ConstraintSystem, Constraints, Error, Expression, Selector},
|
||||||
poly::Rotation,
|
poly::Rotation,
|
||||||
};
|
};
|
||||||
|
@ -128,8 +128,8 @@ impl DecomposeB {
|
||||||
(
|
(
|
||||||
NoteCommitPiece,
|
NoteCommitPiece,
|
||||||
RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
||||||
RangeConstrained<pallas::Base, Option<pallas::Base>>,
|
RangeConstrained<pallas::Base, Value<pallas::Base>>,
|
||||||
RangeConstrained<pallas::Base, Option<pallas::Base>>,
|
RangeConstrained<pallas::Base, Value<pallas::Base>>,
|
||||||
RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
||||||
),
|
),
|
||||||
Error,
|
Error,
|
||||||
|
@ -170,7 +170,7 @@ impl DecomposeB {
|
||||||
layouter: &mut impl Layouter<pallas::Base>,
|
layouter: &mut impl Layouter<pallas::Base>,
|
||||||
b: NoteCommitPiece,
|
b: NoteCommitPiece,
|
||||||
b_0: RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
b_0: RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
||||||
b_1: RangeConstrained<pallas::Base, Option<pallas::Base>>,
|
b_1: RangeConstrained<pallas::Base, Value<pallas::Base>>,
|
||||||
b_2: RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
b_2: RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
||||||
b_3: RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
b_3: RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
||||||
) -> Result<AssignedCell<pallas::Base, pallas::Base>, Error> {
|
) -> Result<AssignedCell<pallas::Base, pallas::Base>, Error> {
|
||||||
|
@ -184,12 +184,7 @@ impl DecomposeB {
|
||||||
.copy_advice(|| "b", &mut region, self.col_l, 0)?;
|
.copy_advice(|| "b", &mut region, self.col_l, 0)?;
|
||||||
b_0.inner()
|
b_0.inner()
|
||||||
.copy_advice(|| "b_0", &mut region, self.col_m, 0)?;
|
.copy_advice(|| "b_0", &mut region, self.col_m, 0)?;
|
||||||
let b_1 = region.assign_advice(
|
let b_1 = region.assign_advice(|| "b_1", self.col_r, 0, || *b_1.inner())?;
|
||||||
|| "b_1",
|
|
||||||
self.col_r,
|
|
||||||
0,
|
|
||||||
|| b_1.inner().ok_or(Error::Synthesis),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
b_2.inner()
|
b_2.inner()
|
||||||
.copy_advice(|| "b_2", &mut region, self.col_m, 1)?;
|
.copy_advice(|| "b_2", &mut region, self.col_m, 1)?;
|
||||||
|
@ -277,8 +272,8 @@ impl DecomposeD {
|
||||||
) -> Result<
|
) -> Result<
|
||||||
(
|
(
|
||||||
NoteCommitPiece,
|
NoteCommitPiece,
|
||||||
RangeConstrained<pallas::Base, Option<pallas::Base>>,
|
RangeConstrained<pallas::Base, Value<pallas::Base>>,
|
||||||
RangeConstrained<pallas::Base, Option<pallas::Base>>,
|
RangeConstrained<pallas::Base, Value<pallas::Base>>,
|
||||||
RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
||||||
),
|
),
|
||||||
Error,
|
Error,
|
||||||
|
@ -313,7 +308,7 @@ impl DecomposeD {
|
||||||
&self,
|
&self,
|
||||||
layouter: &mut impl Layouter<pallas::Base>,
|
layouter: &mut impl Layouter<pallas::Base>,
|
||||||
d: NoteCommitPiece,
|
d: NoteCommitPiece,
|
||||||
d_0: RangeConstrained<pallas::Base, Option<pallas::Base>>,
|
d_0: RangeConstrained<pallas::Base, Value<pallas::Base>>,
|
||||||
d_1: RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
d_1: RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
||||||
d_2: RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
d_2: RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
||||||
z1_d: AssignedCell<pallas::Base, pallas::Base>,
|
z1_d: AssignedCell<pallas::Base, pallas::Base>,
|
||||||
|
@ -326,12 +321,7 @@ impl DecomposeD {
|
||||||
d.inner()
|
d.inner()
|
||||||
.cell_value()
|
.cell_value()
|
||||||
.copy_advice(|| "d", &mut region, self.col_l, 0)?;
|
.copy_advice(|| "d", &mut region, self.col_l, 0)?;
|
||||||
let d_0 = region.assign_advice(
|
let d_0 = region.assign_advice(|| "d_0", self.col_m, 0, || *d_0.inner())?;
|
||||||
|| "d_0",
|
|
||||||
self.col_m,
|
|
||||||
0,
|
|
||||||
|| d_0.inner().ok_or(Error::Synthesis),
|
|
||||||
)?;
|
|
||||||
d_1.inner()
|
d_1.inner()
|
||||||
.copy_advice(|| "d_1", &mut region, self.col_r, 0)?;
|
.copy_advice(|| "d_1", &mut region, self.col_r, 0)?;
|
||||||
|
|
||||||
|
@ -529,7 +519,7 @@ impl DecomposeG {
|
||||||
) -> Result<
|
) -> Result<
|
||||||
(
|
(
|
||||||
NoteCommitPiece,
|
NoteCommitPiece,
|
||||||
RangeConstrained<pallas::Base, Option<pallas::Base>>,
|
RangeConstrained<pallas::Base, Value<pallas::Base>>,
|
||||||
RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
||||||
),
|
),
|
||||||
Error,
|
Error,
|
||||||
|
@ -561,7 +551,7 @@ impl DecomposeG {
|
||||||
&self,
|
&self,
|
||||||
layouter: &mut impl Layouter<pallas::Base>,
|
layouter: &mut impl Layouter<pallas::Base>,
|
||||||
g: NoteCommitPiece,
|
g: NoteCommitPiece,
|
||||||
g_0: RangeConstrained<pallas::Base, Option<pallas::Base>>,
|
g_0: RangeConstrained<pallas::Base, Value<pallas::Base>>,
|
||||||
g_1: RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
g_1: RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
||||||
z1_g: AssignedCell<pallas::Base, pallas::Base>,
|
z1_g: AssignedCell<pallas::Base, pallas::Base>,
|
||||||
) -> Result<AssignedCell<pallas::Base, pallas::Base>, Error> {
|
) -> Result<AssignedCell<pallas::Base, pallas::Base>, Error> {
|
||||||
|
@ -573,12 +563,7 @@ impl DecomposeG {
|
||||||
g.inner()
|
g.inner()
|
||||||
.cell_value()
|
.cell_value()
|
||||||
.copy_advice(|| "g", &mut region, self.col_l, 0)?;
|
.copy_advice(|| "g", &mut region, self.col_l, 0)?;
|
||||||
let g_0 = region.assign_advice(
|
let g_0 = region.assign_advice(|| "g_0", self.col_m, 0, || *g_0.inner())?;
|
||||||
|| "g_0",
|
|
||||||
self.col_m,
|
|
||||||
0,
|
|
||||||
|| g_0.inner().ok_or(Error::Synthesis),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
g_1.inner()
|
g_1.inner()
|
||||||
.copy_advice(|| "g_1", &mut region, self.col_l, 1)?;
|
.copy_advice(|| "g_1", &mut region, self.col_l, 1)?;
|
||||||
|
@ -656,7 +641,7 @@ impl DecomposeH {
|
||||||
(
|
(
|
||||||
NoteCommitPiece,
|
NoteCommitPiece,
|
||||||
RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
||||||
RangeConstrained<pallas::Base, Option<pallas::Base>>,
|
RangeConstrained<pallas::Base, Value<pallas::Base>>,
|
||||||
),
|
),
|
||||||
Error,
|
Error,
|
||||||
> {
|
> {
|
||||||
|
@ -677,7 +662,7 @@ impl DecomposeH {
|
||||||
[
|
[
|
||||||
h_0.value(),
|
h_0.value(),
|
||||||
h_1,
|
h_1,
|
||||||
RangeConstrained::bitrange_of(Some(&pallas::Base::zero()), 0..4),
|
RangeConstrained::bitrange_of(Value::known(&pallas::Base::zero()), 0..4),
|
||||||
],
|
],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
@ -689,7 +674,7 @@ impl DecomposeH {
|
||||||
layouter: &mut impl Layouter<pallas::Base>,
|
layouter: &mut impl Layouter<pallas::Base>,
|
||||||
h: NoteCommitPiece,
|
h: NoteCommitPiece,
|
||||||
h_0: RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
h_0: RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
||||||
h_1: RangeConstrained<pallas::Base, Option<pallas::Base>>,
|
h_1: RangeConstrained<pallas::Base, Value<pallas::Base>>,
|
||||||
) -> Result<AssignedCell<pallas::Base, pallas::Base>, Error> {
|
) -> Result<AssignedCell<pallas::Base, pallas::Base>, Error> {
|
||||||
layouter.assign_region(
|
layouter.assign_region(
|
||||||
|| "NoteCommit MessagePiece h",
|
|| "NoteCommit MessagePiece h",
|
||||||
|
@ -701,12 +686,7 @@ impl DecomposeH {
|
||||||
.copy_advice(|| "h", &mut region, self.col_l, 0)?;
|
.copy_advice(|| "h", &mut region, self.col_l, 0)?;
|
||||||
h_0.inner()
|
h_0.inner()
|
||||||
.copy_advice(|| "h_0", &mut region, self.col_m, 0)?;
|
.copy_advice(|| "h_0", &mut region, self.col_m, 0)?;
|
||||||
let h_1 = region.assign_advice(
|
let h_1 = region.assign_advice(|| "h_1", self.col_r, 0, || *h_1.inner())?;
|
||||||
|| "h_1",
|
|
||||||
self.col_r,
|
|
||||||
0,
|
|
||||||
|| h_1.inner().ok_or(Error::Synthesis),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(h_1)
|
Ok(h_1)
|
||||||
},
|
},
|
||||||
|
@ -1357,10 +1337,10 @@ impl YCanonicity {
|
||||||
&self,
|
&self,
|
||||||
layouter: &mut impl Layouter<pallas::Base>,
|
layouter: &mut impl Layouter<pallas::Base>,
|
||||||
y: AssignedCell<pallas::Base, pallas::Base>,
|
y: AssignedCell<pallas::Base, pallas::Base>,
|
||||||
lsb: RangeConstrained<pallas::Base, Option<pallas::Base>>,
|
lsb: RangeConstrained<pallas::Base, Value<pallas::Base>>,
|
||||||
k_0: RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
k_0: RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
||||||
k_2: RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
k_2: RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>,
|
||||||
k_3: RangeConstrained<pallas::Base, Option<pallas::Base>>,
|
k_3: RangeConstrained<pallas::Base, Value<pallas::Base>>,
|
||||||
j: AssignedCell<pallas::Base, pallas::Base>,
|
j: AssignedCell<pallas::Base, pallas::Base>,
|
||||||
z1_j: AssignedCell<pallas::Base, pallas::Base>,
|
z1_j: AssignedCell<pallas::Base, pallas::Base>,
|
||||||
z13_j: AssignedCell<pallas::Base, pallas::Base>,
|
z13_j: AssignedCell<pallas::Base, pallas::Base>,
|
||||||
|
@ -1381,12 +1361,7 @@ impl YCanonicity {
|
||||||
y.copy_advice(|| "copy y", &mut region, self.advices[5], offset)?;
|
y.copy_advice(|| "copy y", &mut region, self.advices[5], offset)?;
|
||||||
// Witness LSB.
|
// Witness LSB.
|
||||||
let lsb = region
|
let lsb = region
|
||||||
.assign_advice(
|
.assign_advice(|| "witness LSB", self.advices[6], offset, || *lsb.inner())
|
||||||
|| "witness LSB",
|
|
||||||
self.advices[6],
|
|
||||||
offset,
|
|
||||||
|| lsb.inner().ok_or(Error::Synthesis),
|
|
||||||
)
|
|
||||||
// SAFETY: This is sound because we just assigned this cell from a
|
// SAFETY: This is sound because we just assigned this cell from a
|
||||||
// range-constrained value.
|
// range-constrained value.
|
||||||
.map(|cell| RangeConstrained::unsound_unchecked(cell, lsb.num_bits()))?;
|
.map(|cell| RangeConstrained::unsound_unchecked(cell, lsb.num_bits()))?;
|
||||||
|
@ -1401,7 +1376,7 @@ impl YCanonicity {
|
||||||
|| "witness k_3",
|
|| "witness k_3",
|
||||||
self.advices[9],
|
self.advices[9],
|
||||||
offset,
|
offset,
|
||||||
|| k_3.inner().ok_or(Error::Synthesis),
|
|| *k_3.inner(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
lsb
|
lsb
|
||||||
|
@ -1586,7 +1561,7 @@ impl NoteCommitChip {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(in crate::circuit) mod gadgets {
|
pub(in crate::circuit) mod gadgets {
|
||||||
use halo2_proofs::circuit::Chip;
|
use halo2_proofs::circuit::{Chip, Value};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
@ -1817,11 +1792,11 @@ pub(in crate::circuit) mod gadgets {
|
||||||
// Decompose the low 130 bits of a_prime = a + 2^130 - t_P, and output
|
// Decompose the low 130 bits of a_prime = a + 2^130 - t_P, and output
|
||||||
// the running sum at the end of it. If a_prime < 2^130, the running sum
|
// the running sum at the end of it. If a_prime < 2^130, the running sum
|
||||||
// will be 0.
|
// will be 0.
|
||||||
let a_prime = a.value().map(|a| {
|
let a_prime = {
|
||||||
let two_pow_130 = pallas::Base::from_u128(1u128 << 65).square();
|
let two_pow_130 = Value::known(pallas::Base::from_u128(1u128 << 65).square());
|
||||||
let t_p = pallas::Base::from_u128(T_P);
|
let t_p = Value::known(pallas::Base::from_u128(T_P));
|
||||||
a + two_pow_130 - t_p
|
a.value() + two_pow_130 - t_p
|
||||||
});
|
};
|
||||||
let zs = lookup_config.witness_check(
|
let zs = lookup_config.witness_check(
|
||||||
layouter.namespace(|| "Decompose low 130 bits of (a + 2^130 - t_P)"),
|
layouter.namespace(|| "Decompose low 130 bits of (a + 2^130 - t_P)"),
|
||||||
a_prime,
|
a_prime,
|
||||||
|
@ -1856,12 +1831,12 @@ pub(in crate::circuit) mod gadgets {
|
||||||
// Decompose the low 140 bits of b3_c_prime = b_3 + 2^4 c + 2^140 - t_P,
|
// Decompose the low 140 bits of b3_c_prime = b_3 + 2^4 c + 2^140 - t_P,
|
||||||
// and output the running sum at the end of it.
|
// and output the running sum at the end of it.
|
||||||
// If b3_c_prime < 2^140, the running sum will be 0.
|
// If b3_c_prime < 2^140, the running sum will be 0.
|
||||||
let b3_c_prime = b_3.inner().value().zip(c.value()).map(|(b_3, c)| {
|
let b3_c_prime = {
|
||||||
let two_pow_4 = pallas::Base::from(1u64 << 4);
|
let two_pow_4 = Value::known(pallas::Base::from(1u64 << 4));
|
||||||
let two_pow_140 = pallas::Base::from_u128(1u128 << 70).square();
|
let two_pow_140 = Value::known(pallas::Base::from_u128(1u128 << 70).square());
|
||||||
let t_p = pallas::Base::from_u128(T_P);
|
let t_p = Value::known(pallas::Base::from_u128(T_P));
|
||||||
b_3 + (two_pow_4 * c) + two_pow_140 - t_p
|
b_3.inner().value() + (two_pow_4 * c.value()) + two_pow_140 - t_p
|
||||||
});
|
};
|
||||||
|
|
||||||
let zs = lookup_config.witness_check(
|
let zs = lookup_config.witness_check(
|
||||||
layouter.namespace(|| "Decompose low 140 bits of (b_3 + 2^4 c + 2^140 - t_P)"),
|
layouter.namespace(|| "Decompose low 140 bits of (b_3 + 2^4 c + 2^140 - t_P)"),
|
||||||
|
@ -1894,12 +1869,12 @@ pub(in crate::circuit) mod gadgets {
|
||||||
// to 130 bits. z13_f == 0 is directly checked in the gate.
|
// to 130 bits. z13_f == 0 is directly checked in the gate.
|
||||||
// - 0 ≤ e_1 + 2^4 f + 2^140 - t_P < 2^140 (14 ten-bit lookups)
|
// - 0 ≤ e_1 + 2^4 f + 2^140 - t_P < 2^140 (14 ten-bit lookups)
|
||||||
|
|
||||||
let e1_f_prime = e_1.inner().value().zip(f.value()).map(|(e_1, f)| {
|
let e1_f_prime = {
|
||||||
let two_pow_4 = pallas::Base::from(1u64 << 4);
|
let two_pow_4 = Value::known(pallas::Base::from(1u64 << 4));
|
||||||
let two_pow_140 = pallas::Base::from_u128(1u128 << 70).square();
|
let two_pow_140 = Value::known(pallas::Base::from_u128(1u128 << 70).square());
|
||||||
let t_p = pallas::Base::from_u128(T_P);
|
let t_p = Value::known(pallas::Base::from_u128(T_P));
|
||||||
e_1 + (two_pow_4 * f) + two_pow_140 - t_p
|
e_1.inner().value() + (two_pow_4 * f.value()) + two_pow_140 - t_p
|
||||||
});
|
};
|
||||||
|
|
||||||
// Decompose the low 140 bits of e1_f_prime = e_1 + 2^4 f + 2^140 - t_P,
|
// Decompose the low 140 bits of e1_f_prime = e_1 + 2^4 f + 2^140 - t_P,
|
||||||
// and output the running sum at the end of it.
|
// and output the running sum at the end of it.
|
||||||
|
@ -1936,12 +1911,12 @@ pub(in crate::circuit) mod gadgets {
|
||||||
// Decompose the low 130 bits of g1_g2_prime = g_1 + (2^9)g_2 + 2^130 - t_P,
|
// Decompose the low 130 bits of g1_g2_prime = g_1 + (2^9)g_2 + 2^130 - t_P,
|
||||||
// and output the running sum at the end of it.
|
// and output the running sum at the end of it.
|
||||||
// If g1_g2_prime < 2^130, the running sum will be 0.
|
// If g1_g2_prime < 2^130, the running sum will be 0.
|
||||||
let g1_g2_prime = g_1.inner().value().zip(g_2.value()).map(|(g_1, g_2)| {
|
let g1_g2_prime = {
|
||||||
let two_pow_9 = pallas::Base::from(1u64 << 9);
|
let two_pow_9 = Value::known(pallas::Base::from(1u64 << 9));
|
||||||
let two_pow_130 = pallas::Base::from_u128(1u128 << 65).square();
|
let two_pow_130 = Value::known(pallas::Base::from_u128(1u128 << 65).square());
|
||||||
let t_p = pallas::Base::from_u128(T_P);
|
let t_p = Value::known(pallas::Base::from_u128(T_P));
|
||||||
g_1 + (two_pow_9 * g_2) + two_pow_130 - t_p
|
g_1.inner().value() + (two_pow_9 * g_2.value()) + two_pow_130 - t_p
|
||||||
});
|
};
|
||||||
|
|
||||||
let zs = lookup_config.witness_check(
|
let zs = lookup_config.witness_check(
|
||||||
layouter.namespace(|| "Decompose low 130 bits of (g_1 + (2^9)g_2 + 2^130 - t_P)"),
|
layouter.namespace(|| "Decompose low 130 bits of (g_1 + (2^9)g_2 + 2^130 - t_P)"),
|
||||||
|
@ -1966,7 +1941,7 @@ pub(in crate::circuit) mod gadgets {
|
||||||
y_canon: &YCanonicity,
|
y_canon: &YCanonicity,
|
||||||
mut layouter: impl Layouter<pallas::Base>,
|
mut layouter: impl Layouter<pallas::Base>,
|
||||||
y: AssignedCell<pallas::Base, pallas::Base>,
|
y: AssignedCell<pallas::Base, pallas::Base>,
|
||||||
lsb: RangeConstrained<pallas::Base, Option<pallas::Base>>,
|
lsb: RangeConstrained<pallas::Base, Value<pallas::Base>>,
|
||||||
) -> Result<RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>, Error>
|
) -> Result<RangeConstrained<pallas::Base, AssignedCell<pallas::Base, pallas::Base>>, Error>
|
||||||
{
|
{
|
||||||
// Decompose the field element
|
// Decompose the field element
|
||||||
|
@ -1997,16 +1972,11 @@ pub(in crate::circuit) mod gadgets {
|
||||||
|
|
||||||
// Decompose j = LSB + (2)k_0 + (2^10)k_1 using 25 ten-bit lookups.
|
// Decompose j = LSB + (2)k_0 + (2^10)k_1 using 25 ten-bit lookups.
|
||||||
let (j, z1_j, z13_j) = {
|
let (j, z1_j, z13_j) = {
|
||||||
let j = lsb
|
let j = {
|
||||||
.inner()
|
let two = Value::known(pallas::Base::from(2));
|
||||||
.value()
|
let two_pow_10 = Value::known(pallas::Base::from(1 << 10));
|
||||||
.zip(k_0.inner().value())
|
lsb.inner().value() + two * k_0.inner().value() + two_pow_10 * k_1.inner().value()
|
||||||
.zip(k_1.inner().value())
|
};
|
||||||
.map(|((lsb, k_0), k_1)| {
|
|
||||||
let two = pallas::Base::from(2);
|
|
||||||
let two_pow_10 = pallas::Base::from(1 << 10);
|
|
||||||
lsb + two * k_0 + two_pow_10 * k_1
|
|
||||||
});
|
|
||||||
let zs = lookup_config.witness_check(
|
let zs = lookup_config.witness_check(
|
||||||
layouter.namespace(|| "Decompose j = LSB + (2)k_0 + (2^10)k_1"),
|
layouter.namespace(|| "Decompose j = LSB + (2)k_0 + (2^10)k_1"),
|
||||||
j,
|
j,
|
||||||
|
@ -2069,7 +2039,7 @@ mod tests {
|
||||||
use ff::{Field, PrimeField, PrimeFieldBits};
|
use ff::{Field, PrimeField, PrimeFieldBits};
|
||||||
use group::Curve;
|
use group::Curve;
|
||||||
use halo2_proofs::{
|
use halo2_proofs::{
|
||||||
circuit::{Layouter, SimpleFloorPlanner},
|
circuit::{Layouter, SimpleFloorPlanner, Value},
|
||||||
dev::MockProver,
|
dev::MockProver,
|
||||||
plonk::{Circuit, ConstraintSystem, Error},
|
plonk::{Circuit, ConstraintSystem, Error},
|
||||||
};
|
};
|
||||||
|
@ -2084,12 +2054,12 @@ mod tests {
|
||||||
fn note_commit() {
|
fn note_commit() {
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct MyCircuit {
|
struct MyCircuit {
|
||||||
gd_x: Option<pallas::Base>,
|
gd_x: Value<pallas::Base>,
|
||||||
gd_y_lsb: Option<pallas::Base>,
|
gd_y_lsb: Value<pallas::Base>,
|
||||||
pkd_x: Option<pallas::Base>,
|
pkd_x: Value<pallas::Base>,
|
||||||
pkd_y_lsb: Option<pallas::Base>,
|
pkd_y_lsb: Value<pallas::Base>,
|
||||||
rho: Option<pallas::Base>,
|
rho: Value<pallas::Base>,
|
||||||
psi: Option<pallas::Base>,
|
psi: Value<pallas::Base>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Circuit<pallas::Base> for MyCircuit {
|
impl Circuit<pallas::Base> for MyCircuit {
|
||||||
|
@ -2235,7 +2205,7 @@ mod tests {
|
||||||
assign_free_advice(
|
assign_free_advice(
|
||||||
layouter.namespace(|| "witness value"),
|
layouter.namespace(|| "witness value"),
|
||||||
note_commit_config.advices[0],
|
note_commit_config.advices[0],
|
||||||
Some(value),
|
Value::known(value),
|
||||||
)?
|
)?
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2254,8 +2224,11 @@ mod tests {
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let rcm = pallas::Scalar::random(OsRng);
|
let rcm = pallas::Scalar::random(OsRng);
|
||||||
let rcm_gadget =
|
let rcm_gadget = ScalarFixed::new(
|
||||||
ScalarFixed::new(ecc_chip.clone(), layouter.namespace(|| "rcm"), Some(rcm))?;
|
ecc_chip.clone(),
|
||||||
|
layouter.namespace(|| "rcm"),
|
||||||
|
Value::known(rcm),
|
||||||
|
)?;
|
||||||
|
|
||||||
let cm = gadgets::note_commit(
|
let cm = gadgets::note_commit(
|
||||||
layouter.namespace(|| "Hash NoteCommit pieces"),
|
layouter.namespace(|| "Hash NoteCommit pieces"),
|
||||||
|
@ -2273,53 +2246,40 @@ mod tests {
|
||||||
let domain = CommitDomain::new(NOTE_COMMITMENT_PERSONALIZATION);
|
let domain = CommitDomain::new(NOTE_COMMITMENT_PERSONALIZATION);
|
||||||
// Hash g★_d || pk★_d || i2lebsp_{64}(v) || rho || psi
|
// Hash g★_d || pk★_d || i2lebsp_{64}(v) || rho || psi
|
||||||
let lsb = |y_lsb: pallas::Base| y_lsb == pallas::Base::one();
|
let lsb = |y_lsb: pallas::Base| y_lsb == pallas::Base::one();
|
||||||
let point = domain
|
let point = self
|
||||||
.commit(
|
.gd_x
|
||||||
iter::empty()
|
.zip(self.gd_y_lsb)
|
||||||
.chain(
|
.zip(self.pkd_x.zip(self.pkd_y_lsb))
|
||||||
self.gd_x
|
.zip(self.rho.zip(self.psi))
|
||||||
.unwrap()
|
.map(|(((gd_x, gd_y_lsb), (pkd_x, pkd_y_lsb)), (rho, psi))| {
|
||||||
.to_le_bits()
|
domain
|
||||||
.iter()
|
.commit(
|
||||||
.by_vals()
|
iter::empty()
|
||||||
.take(L_ORCHARD_BASE),
|
.chain(
|
||||||
|
gd_x.to_le_bits().iter().by_vals().take(L_ORCHARD_BASE),
|
||||||
|
)
|
||||||
|
.chain(Some(lsb(gd_y_lsb)))
|
||||||
|
.chain(
|
||||||
|
pkd_x
|
||||||
|
.to_le_bits()
|
||||||
|
.iter()
|
||||||
|
.by_vals()
|
||||||
|
.take(L_ORCHARD_BASE),
|
||||||
|
)
|
||||||
|
.chain(Some(lsb(pkd_y_lsb)))
|
||||||
|
.chain(value.to_le_bits().iter().by_vals().take(L_VALUE))
|
||||||
|
.chain(
|
||||||
|
rho.to_le_bits().iter().by_vals().take(L_ORCHARD_BASE),
|
||||||
|
)
|
||||||
|
.chain(
|
||||||
|
psi.to_le_bits().iter().by_vals().take(L_ORCHARD_BASE),
|
||||||
|
),
|
||||||
|
&rcm,
|
||||||
)
|
)
|
||||||
.chain(Some(lsb(self.gd_y_lsb.unwrap())))
|
.unwrap()
|
||||||
.chain(
|
.to_affine()
|
||||||
self.pkd_x
|
});
|
||||||
.unwrap()
|
NonIdentityPoint::new(ecc_chip, layouter.namespace(|| "witness cm"), point)?
|
||||||
.to_le_bits()
|
|
||||||
.iter()
|
|
||||||
.by_vals()
|
|
||||||
.take(L_ORCHARD_BASE),
|
|
||||||
)
|
|
||||||
.chain(Some(lsb(self.pkd_y_lsb.unwrap())))
|
|
||||||
.chain(value.to_le_bits().iter().by_vals().take(L_VALUE))
|
|
||||||
.chain(
|
|
||||||
self.rho
|
|
||||||
.unwrap()
|
|
||||||
.to_le_bits()
|
|
||||||
.iter()
|
|
||||||
.by_vals()
|
|
||||||
.take(L_ORCHARD_BASE),
|
|
||||||
)
|
|
||||||
.chain(
|
|
||||||
self.psi
|
|
||||||
.unwrap()
|
|
||||||
.to_le_bits()
|
|
||||||
.iter()
|
|
||||||
.by_vals()
|
|
||||||
.take(L_ORCHARD_BASE),
|
|
||||||
),
|
|
||||||
&rcm,
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.to_affine();
|
|
||||||
NonIdentityPoint::new(
|
|
||||||
ecc_chip,
|
|
||||||
layouter.namespace(|| "witness cm"),
|
|
||||||
Some(point),
|
|
||||||
)?
|
|
||||||
};
|
};
|
||||||
cm.constrain_equal(layouter.namespace(|| "cm == expected cm"), &expected_cm)
|
cm.constrain_equal(layouter.namespace(|| "cm == expected cm"), &expected_cm)
|
||||||
}
|
}
|
||||||
|
@ -2331,66 +2291,66 @@ mod tests {
|
||||||
// `gd_x` = -1, `pkd_x` = -1 (these have to be x-coordinates of curve points)
|
// `gd_x` = -1, `pkd_x` = -1 (these have to be x-coordinates of curve points)
|
||||||
// `rho` = 0, `psi` = 0
|
// `rho` = 0, `psi` = 0
|
||||||
MyCircuit {
|
MyCircuit {
|
||||||
gd_x: Some(-pallas::Base::one()),
|
gd_x: Value::known(-pallas::Base::one()),
|
||||||
gd_y_lsb: Some(pallas::Base::one()),
|
gd_y_lsb: Value::known(pallas::Base::one()),
|
||||||
pkd_x: Some(-pallas::Base::one()),
|
pkd_x: Value::known(-pallas::Base::one()),
|
||||||
pkd_y_lsb: Some(pallas::Base::one()),
|
pkd_y_lsb: Value::known(pallas::Base::one()),
|
||||||
rho: Some(pallas::Base::zero()),
|
rho: Value::known(pallas::Base::zero()),
|
||||||
psi: Some(pallas::Base::zero()),
|
psi: Value::known(pallas::Base::zero()),
|
||||||
},
|
},
|
||||||
// `rho` = T_Q - 1, `psi` = T_Q - 1
|
// `rho` = T_Q - 1, `psi` = T_Q - 1
|
||||||
MyCircuit {
|
MyCircuit {
|
||||||
gd_x: Some(-pallas::Base::one()),
|
gd_x: Value::known(-pallas::Base::one()),
|
||||||
gd_y_lsb: Some(pallas::Base::zero()),
|
gd_y_lsb: Value::known(pallas::Base::zero()),
|
||||||
pkd_x: Some(-pallas::Base::one()),
|
pkd_x: Value::known(-pallas::Base::one()),
|
||||||
pkd_y_lsb: Some(pallas::Base::zero()),
|
pkd_y_lsb: Value::known(pallas::Base::zero()),
|
||||||
rho: Some(pallas::Base::from_u128(T_Q - 1)),
|
rho: Value::known(pallas::Base::from_u128(T_Q - 1)),
|
||||||
psi: Some(pallas::Base::from_u128(T_Q - 1)),
|
psi: Value::known(pallas::Base::from_u128(T_Q - 1)),
|
||||||
},
|
},
|
||||||
// `rho` = T_Q, `psi` = T_Q
|
// `rho` = T_Q, `psi` = T_Q
|
||||||
MyCircuit {
|
MyCircuit {
|
||||||
gd_x: Some(-pallas::Base::one()),
|
gd_x: Value::known(-pallas::Base::one()),
|
||||||
gd_y_lsb: Some(pallas::Base::one()),
|
gd_y_lsb: Value::known(pallas::Base::one()),
|
||||||
pkd_x: Some(-pallas::Base::one()),
|
pkd_x: Value::known(-pallas::Base::one()),
|
||||||
pkd_y_lsb: Some(pallas::Base::zero()),
|
pkd_y_lsb: Value::known(pallas::Base::zero()),
|
||||||
rho: Some(pallas::Base::from_u128(T_Q)),
|
rho: Value::known(pallas::Base::from_u128(T_Q)),
|
||||||
psi: Some(pallas::Base::from_u128(T_Q)),
|
psi: Value::known(pallas::Base::from_u128(T_Q)),
|
||||||
},
|
},
|
||||||
// `rho` = 2^127 - 1, `psi` = 2^127 - 1
|
// `rho` = 2^127 - 1, `psi` = 2^127 - 1
|
||||||
MyCircuit {
|
MyCircuit {
|
||||||
gd_x: Some(-pallas::Base::one()),
|
gd_x: Value::known(-pallas::Base::one()),
|
||||||
gd_y_lsb: Some(pallas::Base::zero()),
|
gd_y_lsb: Value::known(pallas::Base::zero()),
|
||||||
pkd_x: Some(-pallas::Base::one()),
|
pkd_x: Value::known(-pallas::Base::one()),
|
||||||
pkd_y_lsb: Some(pallas::Base::one()),
|
pkd_y_lsb: Value::known(pallas::Base::one()),
|
||||||
rho: Some(pallas::Base::from_u128((1 << 127) - 1)),
|
rho: Value::known(pallas::Base::from_u128((1 << 127) - 1)),
|
||||||
psi: Some(pallas::Base::from_u128((1 << 127) - 1)),
|
psi: Value::known(pallas::Base::from_u128((1 << 127) - 1)),
|
||||||
},
|
},
|
||||||
// `rho` = 2^127, `psi` = 2^127
|
// `rho` = 2^127, `psi` = 2^127
|
||||||
MyCircuit {
|
MyCircuit {
|
||||||
gd_x: Some(-pallas::Base::one()),
|
gd_x: Value::known(-pallas::Base::one()),
|
||||||
gd_y_lsb: Some(pallas::Base::zero()),
|
gd_y_lsb: Value::known(pallas::Base::zero()),
|
||||||
pkd_x: Some(-pallas::Base::one()),
|
pkd_x: Value::known(-pallas::Base::one()),
|
||||||
pkd_y_lsb: Some(pallas::Base::zero()),
|
pkd_y_lsb: Value::known(pallas::Base::zero()),
|
||||||
rho: Some(pallas::Base::from_u128(1 << 127)),
|
rho: Value::known(pallas::Base::from_u128(1 << 127)),
|
||||||
psi: Some(pallas::Base::from_u128(1 << 127)),
|
psi: Value::known(pallas::Base::from_u128(1 << 127)),
|
||||||
},
|
},
|
||||||
// `rho` = 2^254 - 1, `psi` = 2^254 - 1
|
// `rho` = 2^254 - 1, `psi` = 2^254 - 1
|
||||||
MyCircuit {
|
MyCircuit {
|
||||||
gd_x: Some(-pallas::Base::one()),
|
gd_x: Value::known(-pallas::Base::one()),
|
||||||
gd_y_lsb: Some(pallas::Base::one()),
|
gd_y_lsb: Value::known(pallas::Base::one()),
|
||||||
pkd_x: Some(-pallas::Base::one()),
|
pkd_x: Value::known(-pallas::Base::one()),
|
||||||
pkd_y_lsb: Some(pallas::Base::one()),
|
pkd_y_lsb: Value::known(pallas::Base::one()),
|
||||||
rho: Some(two_pow_254 - pallas::Base::one()),
|
rho: Value::known(two_pow_254 - pallas::Base::one()),
|
||||||
psi: Some(two_pow_254 - pallas::Base::one()),
|
psi: Value::known(two_pow_254 - pallas::Base::one()),
|
||||||
},
|
},
|
||||||
// `rho` = 2^254, `psi` = 2^254
|
// `rho` = 2^254, `psi` = 2^254
|
||||||
MyCircuit {
|
MyCircuit {
|
||||||
gd_x: Some(-pallas::Base::one()),
|
gd_x: Value::known(-pallas::Base::one()),
|
||||||
gd_y_lsb: Some(pallas::Base::one()),
|
gd_y_lsb: Value::known(pallas::Base::one()),
|
||||||
pkd_x: Some(-pallas::Base::one()),
|
pkd_x: Value::known(-pallas::Base::one()),
|
||||||
pkd_y_lsb: Some(pallas::Base::zero()),
|
pkd_y_lsb: Value::known(pallas::Base::zero()),
|
||||||
rho: Some(two_pow_254),
|
rho: Value::known(two_pow_254),
|
||||||
psi: Some(two_pow_254),
|
psi: Value::known(two_pow_254),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -118,6 +118,11 @@ impl OrchardDomain {
|
||||||
rho: *act.nullifier(),
|
rho: *act.nullifier(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constructs a domain from a nullifier.
|
||||||
|
pub fn for_nullifier(nullifier: Nullifier) -> Self {
|
||||||
|
OrchardDomain { rho: nullifier }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Domain for OrchardDomain {
|
impl Domain for OrchardDomain {
|
||||||
|
@ -355,6 +360,28 @@ impl ShieldedOutput<OrchardDomain, COMPACT_NOTE_SIZE> for CompactAction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CompactAction {
|
||||||
|
/// Create a CompactAction from its constituent parts
|
||||||
|
pub fn from_parts(
|
||||||
|
nullifier: Nullifier,
|
||||||
|
cmx: ExtractedNoteCommitment,
|
||||||
|
ephemeral_key: EphemeralKeyBytes,
|
||||||
|
enc_ciphertext: [u8; 52],
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
nullifier,
|
||||||
|
cmx,
|
||||||
|
ephemeral_key,
|
||||||
|
enc_ciphertext,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///Returns the nullifier of the note being spent.
|
||||||
|
pub fn nullifier(&self) -> Nullifier {
|
||||||
|
self.nullifier
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use proptest::prelude::*;
|
use proptest::prelude::*;
|
||||||
|
@ -364,6 +391,7 @@ mod tests {
|
||||||
EphemeralKeyBytes,
|
EphemeralKeyBytes,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::{prf_ock_orchard, CompactAction, OrchardDomain, OrchardNoteEncryption};
|
||||||
use crate::note::note_type::testing::arb_note_type;
|
use crate::note::note_type::testing::arb_note_type;
|
||||||
use crate::note::NoteType;
|
use crate::note::NoteType;
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -381,10 +409,7 @@ mod tests {
|
||||||
Address, Note,
|
Address, Note,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::orchard_parse_note_plaintext_without_memo;
|
||||||
orchard_parse_note_plaintext_without_memo, prf_ock_orchard, CompactAction, OrchardDomain,
|
|
||||||
OrchardNoteEncryption,
|
|
||||||
};
|
|
||||||
|
|
||||||
proptest! {
|
proptest! {
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -472,6 +497,7 @@ mod tests {
|
||||||
};
|
};
|
||||||
|
|
||||||
let note = Note::from_parts(recipient, value, note_type, rho, rseed);
|
let note = Note::from_parts(recipient, value, note_type, rho, rseed);
|
||||||
|
|
||||||
assert_eq!(ExtractedNoteCommitment::from(note.commitment()), cmx);
|
assert_eq!(ExtractedNoteCommitment::from(note.commitment()), cmx);
|
||||||
|
|
||||||
let action = Action::from_parts(
|
let action = Action::from_parts(
|
||||||
|
|
|
@ -421,6 +421,7 @@ pub mod testing {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::note::note_type::testing::{arb_note_type, native_note_type};
|
use crate::note::note_type::testing::{arb_note_type, native_note_type};
|
||||||
|
|
||||||
use crate::note::NoteType;
|
use crate::note::NoteType;
|
||||||
use proptest::prelude::*;
|
use proptest::prelude::*;
|
||||||
|
|
||||||
|
@ -499,8 +500,8 @@ mod tests {
|
||||||
), prop::collection::vec(arb_trapdoor(), n_values))
|
), prop::collection::vec(arb_trapdoor(), n_values))
|
||||||
),
|
),
|
||||||
) {
|
) {
|
||||||
// Test with native and arbitrary note types
|
// Test with native note type (zec)
|
||||||
_bsk_consistent_with_bvk(&native_values, &arb_values, &neg_trapdoors);
|
_bsk_consistent_with_bvk(&native_values, &arb_values, &neg_trapdoors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue