Circuit::synthesize(): Nullifier integrity.

This commit is contained in:
therealyingtong 2021-06-06 20:05:51 +08:00
parent 626ee482bf
commit 48b862f13f
3 changed files with 99 additions and 5 deletions

View File

@ -13,7 +13,7 @@ use pasta_curves::{arithmetic::FieldExt, pallas, vesta};
use crate::{
constants::{
load::{OrchardFixedBasesFull, ValueCommitV},
load::{NullifierK, OrchardFixedBasesFull, ValueCommitV},
MERKLE_DEPTH_ORCHARD,
},
keys::{
@ -25,7 +25,7 @@ use crate::{
ExtractedNoteCommitment,
},
primitives::{
poseidon,
poseidon::{self, ConstantLength},
redpallas::{SpendAuth, VerificationKey},
},
spec::NonIdentityPallasPoint,
@ -35,9 +35,12 @@ use crate::{
use gadget::{
ecc::{
chip::{EccChip, EccConfig},
FixedPoint, FixedPointShort, Point,
FixedPoint, FixedPointBaseField, FixedPointShort, Point,
},
poseidon::{
Hash as PoseidonHash, Pow5T3Chip as PoseidonChip, Pow5T3Config as PoseidonConfig,
StateWord, Word,
},
poseidon::{Pow5T3Chip as PoseidonChip, Pow5T3Config as PoseidonConfig},
sinsemilla::{
chip::{SinsemillaChip, SinsemillaConfig, SinsemillaHashDomains},
merkle::{
@ -440,6 +443,92 @@ impl plonk::Circuit<pallas::Base> for Circuit {
commitment.add(layouter.namespace(|| "cv_net"), &blind)?
};
// Nullifier integrity
// TODO: constrain to equal public input nf_old
let _nf_old = {
// nk_rho_old = poseidon_hash(nk, rho_old)
let nk_rho_old = {
let message = [nk, rho_old];
let poseidon_message = layouter.assign_region(
|| "load message",
|mut region| {
let mut message_word = |i: usize| {
let value = message[i].value();
let var = region.assign_advice(
|| format!("load message_{}", i),
config.poseidon_config.state[i],
0,
|| value.ok_or(plonk::Error::SynthesisError),
)?;
region.constrain_equal(var, message[i].cell())?;
Ok(Word::<_, _, poseidon::OrchardNullifier, 3, 2> {
inner: StateWord::new(var, value),
})
};
Ok([message_word(0)?, message_word(1)?])
},
)?;
let poseidon_hasher = PoseidonHash::init(
config.poseidon_chip(),
layouter.namespace(|| "Poseidon init"),
ConstantLength::<2>,
)?;
let poseidon_output = poseidon_hasher.hash(
layouter.namespace(|| "Poseidon hash (nk, rho_old)"),
poseidon_message,
)?;
let poseidon_output: CellValue<pallas::Base> = poseidon_output.inner.into();
poseidon_output
};
// Add hash output to psi using standard PLONK
// `scalar` = poseidon_hash(nk, rho_old) + psi_old.
//
let scalar = {
let scalar_val = nk_rho_old
.value()
.zip(psi_old.value())
.map(|(nk_rho_old, psi_old)| nk_rho_old + psi_old);
let scalar = self.load_private(
layouter.namespace(|| "poseidon_hash(nk, rho_old) + psi_old"),
config.advices[0],
scalar_val,
)?;
config.plonk_chip().add(
layouter.namespace(|| "poseidon_hash(nk, rho_old) + psi_old"),
nk_rho_old,
psi_old,
scalar,
Some(pallas::Base::one()),
Some(pallas::Base::one()),
Some(pallas::Base::one()),
)?;
scalar
};
// Multiply scalar by NullifierK
// `product` = [poseidon_hash(nk, rho_old) + psi_old] NullifierK.
//
let product = {
let nullifier_k = FixedPointBaseField::from_inner(ecc_chip.clone(), NullifierK);
nullifier_k.mul(
layouter.namespace(|| "[poseidon_output + psi_old] NullifierK"),
scalar,
)?
};
// Add cm_old to multiplied fixed base to get nf_old
// cm_old + [poseidon_output + psi_old] NullifierK
cm_old
.add(layouter.namespace(|| "nf_old"), &product)?
.extract_p()
};
Ok(())
}
}

View File

@ -1,6 +1,7 @@
use pasta_curves::pallas;
use ecc::chip::EccChip;
use poseidon::Pow5T3Chip as PoseidonChip;
use sinsemilla::merkle::chip::MerkleChip;
use utilities::plonk::PLONKChip;
@ -25,4 +26,8 @@ impl super::Config {
pub(super) fn merkle_chip_2(&self) -> MerkleChip {
MerkleChip::construct(self.merkle_config_2.clone())
}
pub(super) fn poseidon_chip(&self) -> PoseidonChip<pallas::Base> {
PoseidonChip::construct(self.poseidon_config.clone())
}
}

View File

@ -16,7 +16,7 @@ const WIDTH: usize = 3;
/// Configuration for an [`Pow5T3Chip`].
#[derive(Clone, Debug)]
pub struct Pow5T3Config<F: FieldExt> {
state: [Column<Advice>; WIDTH],
pub(in crate::circuit) state: [Column<Advice>; WIDTH],
partial_sbox: Column<Advice>,
rc_a: [Column<Fixed>; WIDTH],
rc_b: [Column<Fixed>; WIDTH],