From 48b862f13fd7f33177ed96af86174d3761b180c0 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Sun, 6 Jun 2021 20:05:51 +0800 Subject: [PATCH] Circuit::synthesize(): Nullifier integrity. --- src/circuit.rs | 97 +++++++++++++++++++++++++-- src/circuit/gadget.rs | 5 ++ src/circuit/gadget/poseidon/pow5t3.rs | 2 +- 3 files changed, 99 insertions(+), 5 deletions(-) diff --git a/src/circuit.rs b/src/circuit.rs index 9e5a8d0e..e942f7c3 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -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 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 = 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(()) } } diff --git a/src/circuit/gadget.rs b/src/circuit/gadget.rs index 888f537b..dbcf8450 100644 --- a/src/circuit/gadget.rs +++ b/src/circuit/gadget.rs @@ -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 { + PoseidonChip::construct(self.poseidon_config.clone()) + } } diff --git a/src/circuit/gadget/poseidon/pow5t3.rs b/src/circuit/gadget/poseidon/pow5t3.rs index 1ec4fdd4..25e6b659 100644 --- a/src/circuit/gadget/poseidon/pow5t3.rs +++ b/src/circuit/gadget/poseidon/pow5t3.rs @@ -16,7 +16,7 @@ const WIDTH: usize = 3; /// Configuration for an [`Pow5T3Chip`]. #[derive(Clone, Debug)] pub struct Pow5T3Config { - state: [Column; WIDTH], + pub(in crate::circuit) state: [Column; WIDTH], partial_sbox: Column, rc_a: [Column; WIDTH], rc_b: [Column; WIDTH],