diff --git a/taiga_halo2/deprecated/taiga_sudoku/app_vp.rs b/taiga_halo2/deprecated/taiga_sudoku/app_vp.rs index 6d1fe94f..6676020b 100644 --- a/taiga_halo2/deprecated/taiga_sudoku/app_vp.rs +++ b/taiga_halo2/deprecated/taiga_sudoku/app_vp.rs @@ -666,7 +666,7 @@ fn test_halo2_sudoku_app_vp_circuit_init() { output_notes[0].note_type.app_data_static = poseidon_hash(encoded_init_state, current_state.encode()); output_notes[0].value = 1u64; - let owned_note_pub_id = output_notes[0].commitment().get_x(); + let owned_note_pub_id = output_notes[0].commitment().inner(); SudokuAppValidityPredicateCircuit { owned_note_pub_id, input_notes, diff --git a/taiga_halo2/deprecated/taiga_sudoku/dealer_intent_app_vp.rs b/taiga_halo2/deprecated/taiga_sudoku/dealer_intent_app_vp.rs index 5d24d028..2a1d13d5 100644 --- a/taiga_halo2/deprecated/taiga_sudoku/dealer_intent_app_vp.rs +++ b/taiga_halo2/deprecated/taiga_sudoku/dealer_intent_app_vp.rs @@ -372,7 +372,7 @@ fn test_halo2_dealer_intent_vp_circuit() { sudoku_app_vk, ); let encoded_solution = pallas::Base::random(&mut rng); - let owned_note_pub_id = output_notes[0].commitment().get_x(); + let owned_note_pub_id = output_notes[0].commitment().inner(); DealerIntentValidityPredicateCircuit { owned_note_pub_id, input_notes, diff --git a/taiga_halo2/examples/tx_examples/cascaded_partial_transactions.rs b/taiga_halo2/examples/tx_examples/cascaded_partial_transactions.rs index 84e7e764..99141997 100644 --- a/taiga_halo2/examples/tx_examples/cascaded_partial_transactions.rs +++ b/taiga_halo2/examples/tx_examples/cascaded_partial_transactions.rs @@ -45,7 +45,7 @@ pub fn create_transaction(mut rng: R) -> Transaction { let input_note_3 = create_random_token_note(&mut rng, "xan", 3u64, rho, alice_nk, &alice_auth); let cascade_intent_note = create_intent_note( &mut rng, - input_note_3.commitment().get_x(), + input_note_3.commitment().inner(), input_note_2.get_nf().unwrap(), alice_nk, ); @@ -108,7 +108,7 @@ pub fn create_transaction(mut rng: R) -> Transaction { let intent_note_proving_info = { let intent_vp = CascadeIntentValidityPredicateCircuit { - owned_note_pub_id: cascade_intent_note.commitment().get_x(), + owned_note_pub_id: cascade_intent_note.commitment().inner(), input_notes, output_notes, cascade_note_cm: cascade_intent_note.get_app_data_static(), diff --git a/taiga_halo2/examples/tx_examples/partial_fulfillment_token_swap.rs b/taiga_halo2/examples/tx_examples/partial_fulfillment_token_swap.rs index 105ce0cc..774b3ddc 100644 --- a/taiga_halo2/examples/tx_examples/partial_fulfillment_token_swap.rs +++ b/taiga_halo2/examples/tx_examples/partial_fulfillment_token_swap.rs @@ -38,6 +38,7 @@ pub fn create_token_intent_ptx( pallas::Scalar, NullifierKeyContainer, pallas::Base, + pallas::Base, Nullifier, ) { let input_auth = TokenAuthorization::from_sk_vk(&input_auth_sk, &COMPRESSED_TOKEN_AUTH_VK); @@ -48,14 +49,14 @@ pub fn create_token_intent_ptx( create_random_token_note(&mut rng, &sell.name, sell.value, rho, input_nk, &input_auth); // output intent note - // Use the same address as that in the input note. They can be different. - let receiver_address = input_note.get_address(); + let input_note_nk_com = input_note.get_nk_commitment(); let input_note_nf = input_note.get_nf().unwrap(); let intent_note = create_intent_note( &mut rng, &sell, &buy, - receiver_address, + input_note_nk_com, + input_note.app_data_dynamic, input_note_nf, input_nk, ); @@ -85,12 +86,13 @@ pub fn create_token_intent_ptx( // Create the intent note proving info let intent_note_proving_info = { let intent_vp = PartialFulfillmentIntentValidityPredicateCircuit { - owned_note_pub_id: intent_note.commitment().get_x(), + owned_note_pub_id: intent_note.commitment().inner(), input_notes, output_notes, sell: sell.clone(), buy, - receiver_address, + receiver_nk_com: input_note_nk_com, + receiver_app_data_dynamic: input_note.app_data_dynamic, }; OutputNoteProvingInfo::new(intent_note, Box::new(intent_vp), vec![]) @@ -118,7 +120,14 @@ pub fn create_token_intent_ptx( &mut rng, ); - (ptx, r, input_nk, receiver_address, rho) + ( + ptx, + r, + input_nk, + input_note_nk_com, + input_note.app_data_dynamic, + rho, + ) } #[allow(clippy::too_many_arguments)] @@ -130,11 +139,20 @@ pub fn consume_token_intent_ptx( returned_note_value: u64, input_rho: Nullifier, input_nk: NullifierKeyContainer, // NullifierKeyContainer::Key - input_address: pallas::Base, + receiver_nk_com: pallas::Base, + receiver_app_data_dynamic: pallas::Base, output_auth_pk: pallas::Point, ) -> (ShieldedPartialTransaction, pallas::Scalar) { // input intent note - let intent_note = create_intent_note(&mut rng, &sell, &buy, input_address, input_rho, input_nk); + let intent_note = create_intent_note( + &mut rng, + &sell, + &buy, + receiver_nk_com, + receiver_app_data_dynamic, + input_rho, + input_nk, + ); // output notes let input_note_nf = intent_note.get_nf().unwrap(); @@ -147,8 +165,6 @@ pub fn consume_token_intent_ptx( input_nk, &output_auth, ); - let address = bought_note.get_address(); - assert_eq!(address, input_address); // padding the zero note let padding_input_note = Note::random_padding_input_note(&mut rng); @@ -176,7 +192,8 @@ pub fn consume_token_intent_ptx( output_notes, sell: sell.clone(), buy: buy.clone(), - receiver_address: input_address, + receiver_nk_com, + receiver_app_data_dynamic, }; InputNoteProvingInfo::new( @@ -238,7 +255,7 @@ pub fn create_token_swap_transaction(mut rng: R) -> Tran name: "eth".to_string(), value: 10u64, }; - let (alice_ptx, alice_r, intent_nk, receiver_address, intent_rho) = + let (alice_ptx, alice_r, intent_nk, receiver_nk_com, receiver_app_data_dynamic, intent_rho) = create_token_intent_ptx(&mut rng, sell.clone(), buy.clone(), alice_auth_sk, alice_nk); // Bob creates the partial transaction with 1 DOLPHIN input and 5 BTC output @@ -268,7 +285,8 @@ pub fn create_token_swap_transaction(mut rng: R) -> Tran 1u64, intent_rho, intent_nk, - receiver_address, + receiver_nk_com, + receiver_app_data_dynamic, alice_auth_pk, ); diff --git a/taiga_halo2/examples/tx_examples/token_swap_with_intent.rs b/taiga_halo2/examples/tx_examples/token_swap_with_intent.rs index 8d2381de..3ceb7335 100644 --- a/taiga_halo2/examples/tx_examples/token_swap_with_intent.rs +++ b/taiga_halo2/examples/tx_examples/token_swap_with_intent.rs @@ -40,6 +40,7 @@ pub fn create_token_intent_ptx( pallas::Scalar, NullifierKeyContainer, pallas::Base, + pallas::Base, Nullifier, ) { let input_auth = TokenAuthorization::from_sk_vk(&input_auth_sk, &COMPRESSED_TOKEN_AUTH_VK); @@ -56,14 +57,14 @@ pub fn create_token_intent_ptx( ); // output intent note - // Use the same address as that in the input note. They can be different. - let receiver_address = input_note.get_address(); let input_note_nf = input_note.get_nf().unwrap(); + let input_note_nk_com = input_note.get_nk_commitment(); let intent_note = create_intent_note( &mut rng, &condition1, &condition2, - receiver_address, + input_note_nk_com, + input_note.app_data_dynamic, input_note_nf, input_nk, ); @@ -93,12 +94,13 @@ pub fn create_token_intent_ptx( // Create the intent note proving info let intent_note_proving_info = { let intent_vp = OrRelationIntentValidityPredicateCircuit { - owned_note_pub_id: intent_note.commitment().get_x(), + owned_note_pub_id: intent_note.commitment().inner(), input_notes, output_notes, condition1, condition2, - receiver_address, + receiver_nk_com: input_note_nk_com, + receiver_app_data_dynamic: input_note.app_data_dynamic, }; OutputNoteProvingInfo::new(intent_note, Box::new(intent_vp), vec![]) @@ -126,7 +128,14 @@ pub fn create_token_intent_ptx( &mut rng, ); - (ptx, r, input_nk, receiver_address, rho) + ( + ptx, + r, + input_nk, + input_note_nk_com, + input_note.app_data_dynamic, + rho, + ) } #[allow(clippy::too_many_arguments)] @@ -136,7 +145,8 @@ pub fn consume_token_intent_ptx( condition2: Condition, input_rho: Nullifier, input_nk: NullifierKeyContainer, // NullifierKeyContainer::Key - input_address: pallas::Base, + receiver_nk_com: pallas::Base, + receiver_app_data_dynamic: pallas::Base, output_token: &str, output_value: u64, output_auth_pk: pallas::Point, @@ -146,7 +156,8 @@ pub fn consume_token_intent_ptx( &mut rng, &condition1, &condition2, - input_address, + receiver_nk_com, + receiver_app_data_dynamic, input_rho, input_nk, ); @@ -162,8 +173,6 @@ pub fn consume_token_intent_ptx( input_nk.to_commitment(), &output_auth, ); - let address = output_note.get_address(); - assert_eq!(address, input_address); // padding the zero notes let padding_input_note = Note::random_padding_input_note(&mut rng); @@ -183,7 +192,8 @@ pub fn consume_token_intent_ptx( output_notes, condition1, condition2, - receiver_address: input_address, + receiver_nk_com, + receiver_app_data_dynamic, }; InputNoteProvingInfo::new( @@ -242,15 +252,16 @@ pub fn create_token_swap_intent_transaction(mut rng: R) token_name: "monkey".to_string(), token_value: 2u64, }; - let (alice_ptx, alice_r, intent_nk, receiver_address, intent_rho) = create_token_intent_ptx( - &mut rng, - condition1.clone(), - condition2.clone(), - "btc", - 5u64, - alice_auth_sk, - alice_nk, - ); + let (alice_ptx, alice_r, intent_nk, receiver_nk_com, receiver_app_data_dynamic, intent_rho) = + create_token_intent_ptx( + &mut rng, + condition1.clone(), + condition2.clone(), + "btc", + 5u64, + alice_auth_sk, + alice_nk, + ); // Bob creates the partial transaction with 1 DOLPHIN input and 5 BTC output let bob_auth_sk = pallas::Scalar::random(&mut rng); @@ -277,7 +288,8 @@ pub fn create_token_swap_intent_transaction(mut rng: R) condition2, intent_rho, intent_nk, - receiver_address, + receiver_nk_com, + receiver_app_data_dynamic, "dolphin", 1u64, alice_auth_pk, diff --git a/taiga_halo2/src/action.rs b/taiga_halo2/src/action.rs index 8e10e021..2752f924 100644 --- a/taiga_halo2/src/action.rs +++ b/taiga_halo2/src/action.rs @@ -30,8 +30,8 @@ pub struct ActionInstance { /// The nullifier of input note. pub nf: Nullifier, /// The commitment to the output note. - pub cm_x: pallas::Base, - /// The commitment to net value + pub cm: pallas::Base, + /// net value commitment pub cv_net: ValueCommitment, /// The commitment to input note application(static) vp pub input_vp_commitment: ValidityPredicateCommitment, @@ -56,7 +56,7 @@ impl ActionInstance { vec![ self.nf.inner(), self.anchor, - self.cm_x, + self.cm, self.cv_net.get_x(), self.cv_net.get_y(), input_vp_commitment[0], @@ -73,7 +73,7 @@ impl BorshSerialize for ActionInstance { use ff::PrimeField; writer.write_all(&self.anchor.to_repr())?; writer.write_all(&self.nf.to_bytes())?; - writer.write_all(&self.cm_x.to_repr())?; + writer.write_all(&self.cm.to_repr())?; writer.write_all(&self.cv_net.to_bytes())?; writer.write_all(&self.input_vp_commitment.to_bytes())?; writer.write_all(&self.output_vp_commitment.to_bytes())?; @@ -92,9 +92,9 @@ impl BorshDeserialize for ActionInstance { let nf_bytes = <[u8; 32]>::deserialize_reader(reader)?; let nf = Option::from(Nullifier::from_bytes(nf_bytes)) .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "nf not in field"))?; - let cm_x_bytes = <[u8; 32]>::deserialize_reader(reader)?; - let cm_x = Option::from(pallas::Base::from_repr(cm_x_bytes)) - .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "cm_x not in field"))?; + let cm_bytes = <[u8; 32]>::deserialize_reader(reader)?; + let cm = Option::from(pallas::Base::from_repr(cm_bytes)) + .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "cm not in field"))?; let cv_net_bytes = <[u8; 32]>::deserialize_reader(reader)?; let cv_net = Option::from(ValueCommitment::from_bytes(cv_net_bytes)) .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "cv_net not in field"))?; @@ -108,7 +108,7 @@ impl BorshDeserialize for ActionInstance { Ok(ActionInstance { anchor, nf, - cm_x, + cm, cv_net, input_vp_commitment, output_vp_commitment, @@ -167,7 +167,7 @@ impl ActionInfo { "The nf of input note should be equal to the rho of output note" ); - let cm_x = self.output_note.commitment().get_x(); + let cm = self.output_note.commitment().inner(); let anchor = { let cm_node = Node::from_note(&self.input_note); self.input_merkle_path.root(cm_node).inner() @@ -186,7 +186,7 @@ impl ActionInfo { let action = ActionInstance { nf, - cm_x, + cm, anchor, cv_net, input_vp_commitment, diff --git a/taiga_halo2/src/circuit/action_circuit.rs b/taiga_halo2/src/circuit/action_circuit.rs index 37bf5692..3c906859 100644 --- a/taiga_halo2/src/circuit/action_circuit.rs +++ b/taiga_halo2/src/circuit/action_circuit.rs @@ -1,25 +1,31 @@ use crate::circuit::blake2s::{vp_commitment_gadget, Blake2sChip, Blake2sConfig}; -use crate::circuit::gadgets::{add::AddChip, assign_free_advice}; +use crate::circuit::gadgets::assign_free_advice; use crate::circuit::hash_to_curve::HashToCurveConfig; use crate::circuit::integrity::{check_input_note, check_output_note, compute_value_commitment}; use crate::circuit::merkle_circuit::{ merkle_poseidon_gadget, MerklePoseidonChip, MerklePoseidonConfig, }; -use crate::circuit::note_circuit::{NoteChip, NoteCommitmentChip, NoteConfig}; use crate::constant::{ - NoteCommitmentDomain, NoteCommitmentHashDomain, TaigaFixedBases, - ACTION_ANCHOR_PUBLIC_INPUT_ROW_IDX, ACTION_INPUT_VP_CM_1_ROW_IDX, ACTION_INPUT_VP_CM_2_ROW_IDX, - ACTION_NET_VALUE_CM_X_PUBLIC_INPUT_ROW_IDX, ACTION_NET_VALUE_CM_Y_PUBLIC_INPUT_ROW_IDX, - ACTION_NF_PUBLIC_INPUT_ROW_IDX, ACTION_OUTPUT_CM_PUBLIC_INPUT_ROW_IDX, - ACTION_OUTPUT_VP_CM_1_ROW_IDX, ACTION_OUTPUT_VP_CM_2_ROW_IDX, TAIGA_COMMITMENT_TREE_DEPTH, + TaigaFixedBases, ACTION_ANCHOR_PUBLIC_INPUT_ROW_IDX, ACTION_INPUT_VP_CM_1_ROW_IDX, + ACTION_INPUT_VP_CM_2_ROW_IDX, ACTION_NET_VALUE_CM_X_PUBLIC_INPUT_ROW_IDX, + ACTION_NET_VALUE_CM_Y_PUBLIC_INPUT_ROW_IDX, ACTION_NF_PUBLIC_INPUT_ROW_IDX, + ACTION_OUTPUT_CM_PUBLIC_INPUT_ROW_IDX, ACTION_OUTPUT_VP_CM_1_ROW_IDX, + ACTION_OUTPUT_VP_CM_2_ROW_IDX, TAIGA_COMMITMENT_TREE_DEPTH, }; use crate::merkle_tree::LR; use crate::note::Note; -use halo2_gadgets::{ecc::chip::EccChip, sinsemilla::chip::SinsemillaChip}; +use halo2_gadgets::{ + ecc::chip::{EccChip, EccConfig}, + poseidon::{primitives as poseidon, Pow5Chip as PoseidonChip, Pow5Config as PoseidonConfig}, + utilities::lookup_range_check::LookupRangeCheckConfig, +}; use halo2_proofs::{ circuit::{floor_planner, Layouter, Value}, - plonk::{Advice, Circuit, Column, ConstraintSystem, Constraints, Error, Instance, Selector}, + plonk::{ + Advice, Circuit, Column, ConstraintSystem, Constraints, Error, Instance, Selector, + TableColumn, + }, poly::Rotation, }; use pasta_curves::pallas; @@ -28,7 +34,9 @@ use pasta_curves::pallas; pub struct ActionConfig { instances: Column, advices: [Column; 10], - note_config: NoteConfig, + table_idx: TableColumn, + ecc_config: EccConfig, + poseidon_config: PoseidonConfig, merkle_config: MerklePoseidonConfig, merkle_path_selector: Selector, hash_to_curve_config: HashToCurveConfig, @@ -81,6 +89,33 @@ impl Circuit for ActionCircuit { meta.enable_equality(*advice); } + let table_idx = meta.lookup_table_column(); + + let range_check = LookupRangeCheckConfig::configure(meta, advices[9], table_idx); + + let lagrange_coeffs = [ + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + ]; + meta.enable_constant(lagrange_coeffs[0]); + + let ecc_config = + EccChip::::configure(meta, advices, lagrange_coeffs, range_check); + + let poseidon_config = PoseidonChip::configure::( + meta, + advices[6..9].try_into().unwrap(), + advices[5], + lagrange_coeffs[2..5].try_into().unwrap(), + lagrange_coeffs[5..8].try_into().unwrap(), + ); + let merkle_path_selector = meta.selector(); meta.create_gate("merkle path check", |meta| { let merkle_path_selector = meta.query_selector(merkle_path_selector); @@ -97,23 +132,23 @@ impl Circuit for ActionCircuit { ) }); - let note_config = NoteChip::configure(meta, instances, advices); - let merkle_config = MerklePoseidonChip::configure( meta, advices[..5].try_into().unwrap(), - note_config.poseidon_config.clone(), + poseidon_config.clone(), ); let hash_to_curve_config = - HashToCurveConfig::configure(meta, advices, note_config.poseidon_config.clone()); + HashToCurveConfig::configure(meta, advices, poseidon_config.clone()); let blake2s_config = Blake2sConfig::configure(meta, advices); Self::Config { instances, advices, - note_config, + table_idx, + ecc_config, + poseidon_config, merkle_config, merkle_path_selector, hash_to_curve_config, @@ -126,25 +161,23 @@ impl Circuit for ActionCircuit { config: Self::Config, mut layouter: impl Layouter, ) -> Result<(), Error> { - // Load the Sinsemilla generator lookup table used by the whole circuit. - SinsemillaChip::::load( - config.note_config.sinsemilla_config.clone(), - &mut layouter, - )?; - - // Construct a Sinsemilla chip - let sinsemilla_chip = - SinsemillaChip::construct(config.note_config.sinsemilla_config.clone()); - // Construct an ECC chip - let ecc_chip = EccChip::construct(config.note_config.ecc_config); - - // Construct a NoteCommit chip - let note_commit_chip = - NoteCommitmentChip::construct(config.note_config.note_commit_config.clone()); - - // Construct an add chip - let add_chip = AddChip::::construct(config.note_config.add_config, ()); + let ecc_chip = EccChip::construct(config.ecc_config); + layouter.assign_table( + || "table_idx", + |mut table| { + // We generate the row values lazily (we only need them during keygen). + for index in 0..(1 << 10) { + table.assign_cell( + || "table_idx", + config.table_idx, + index, + || Value::known(pallas::Base::from(index as u64)), + )?; + } + Ok(()) + }, + )?; // Construct a merkle chip let merkle_chip = MerklePoseidonChip::construct(config.merkle_config); @@ -158,11 +191,7 @@ impl Circuit for ActionCircuit { layouter.namespace(|| "check input note"), config.advices, config.instances, - ecc_chip.clone(), - sinsemilla_chip.clone(), - note_commit_chip.clone(), - config.note_config.poseidon_config.clone(), - add_chip, + config.poseidon_config.clone(), self.input_note, ACTION_NF_PUBLIC_INPUT_ROW_IDX, )?; @@ -171,7 +200,7 @@ impl Circuit for ActionCircuit { let root = merkle_poseidon_gadget( layouter.namespace(|| "poseidon merkle"), merkle_chip, - input_note_variables.cm_x, + input_note_variables.cm, &self.merkle_path, )?; @@ -180,10 +209,7 @@ impl Circuit for ActionCircuit { layouter.namespace(|| "check output note"), config.advices, config.instances, - ecc_chip.clone(), - sinsemilla_chip, - note_commit_chip, - config.note_config.poseidon_config, + config.poseidon_config, self.output_note, input_note_variables.nf, ACTION_OUTPUT_CM_PUBLIC_INPUT_ROW_IDX, diff --git a/taiga_halo2/src/circuit/integrity.rs b/taiga_halo2/src/circuit/integrity.rs index 5880b559..de7b2aa9 100644 --- a/taiga_halo2/src/circuit/integrity.rs +++ b/taiga_halo2/src/circuit/integrity.rs @@ -1,29 +1,14 @@ use crate::circuit::{ - gadgets::{ - add::{AddChip, AddInstructions}, - assign_free_advice, assign_free_constant, - poseidon_hash::poseidon_hash_gadget, - }, + gadgets::{assign_free_advice, assign_free_constant, poseidon_hash::poseidon_hash_gadget}, hash_to_curve::{hash_to_curve_circuit, HashToCurveConfig}, - note_circuit::{note_commitment_gadget, NoteCommitmentChip}, vp_circuit::{InputNoteVariables, NoteVariables, OutputNoteVariables}, }; -use crate::constant::{ - BaseFieldGenerators, NoteCommitmentDomain, NoteCommitmentHashDomain, TaigaFixedBases, - TaigaFixedBasesFull, POSEIDON_TO_CURVE_INPUT_LEN, -}; +use crate::constant::{TaigaFixedBases, TaigaFixedBasesFull, POSEIDON_TO_CURVE_INPUT_LEN}; use crate::note::Note; use crate::utils::poseidon_to_curve; use halo2_gadgets::{ - ecc::{ - chip::EccChip, FixedPoint, FixedPointBaseField, NonIdentityPoint, Point, ScalarFixed, - ScalarVar, - }, - poseidon::{ - primitives as poseidon, primitives::ConstantLength, Hash as PoseidonHash, - Pow5Chip as PoseidonChip, Pow5Config as PoseidonConfig, - }, - sinsemilla::chip::SinsemillaChip, + ecc::{chip::EccChip, FixedPoint, NonIdentityPoint, Point, ScalarFixed, ScalarVar}, + poseidon::Pow5Config as PoseidonConfig, }; use halo2_proofs::{ circuit::{AssignedCell, Layouter, Value}, @@ -33,43 +18,55 @@ use pasta_curves::group::Curve; use pasta_curves::pallas; use std::ops::Neg; -// cm is a point +#[allow(clippy::too_many_arguments)] +pub fn note_commitment_circuit( + mut layouter: impl Layouter, + poseidon_config: PoseidonConfig, + app_vp: AssignedCell, + app_data_static: AssignedCell, + app_data_dynamic: AssignedCell, + nk_com: AssignedCell, + rho: AssignedCell, + psi: AssignedCell, + value: AssignedCell, + is_merkle_checked: AssignedCell, + rcm: AssignedCell, +) -> Result, Error> { + // TODO: compose the value and is_merkle_checked to one field in order to save one poseidon absorb + let poseidon_message = [ + app_vp, + app_data_static, + app_data_dynamic, + nk_com, + rho, + psi, + is_merkle_checked, + value, + rcm, + ]; + poseidon_hash_gadget( + poseidon_config, + layouter.namespace(|| "note commitment"), + poseidon_message, + ) +} + +// cm is a field element #[allow(clippy::too_many_arguments)] pub fn nullifier_circuit( mut layouter: impl Layouter, - poseidon_chip: PoseidonChip, - add_chip: AddChip, - ecc_chip: EccChip, + poseidon_config: PoseidonConfig, nk: AssignedCell, rho: AssignedCell, psi: AssignedCell, - cm: &Point>, + cm: AssignedCell, ) -> Result, Error> { - let poseidon_message = [nk, rho]; - let poseidon_hasher = - PoseidonHash::<_, _, poseidon::P128Pow5T3, ConstantLength<2>, 3, 2>::init( - poseidon_chip, - layouter.namespace(|| "Poseidon init"), - )?; - let hash_nk_rho = poseidon_hasher.hash( - layouter.namespace(|| "Poseidon_hash(nk, rho)"), + let poseidon_message = [nk, rho, psi, cm]; + poseidon_hash_gadget( + poseidon_config, + layouter.namespace(|| "derive nullifier"), poseidon_message, - )?; - - let hash_nk_rho_add_psi = add_chip.add( - layouter.namespace(|| "scalar = poseidon_hash(nk, rho) + psi"), - &hash_nk_rho, - &psi, - )?; - - let nullifier_k = FixedPointBaseField::from_inner(ecc_chip, BaseFieldGenerators::BaseGenerator); - let hash_nk_rho_add_psi_mul_k = nullifier_k.mul( - layouter.namespace(|| "hash_nk_rho_add_psi * nullifier_k"), - hash_nk_rho_add_psi, - )?; - - cm.add(layouter.namespace(|| "nf"), &hash_nk_rho_add_psi_mul_k) - .map(|res| res.extract_p().inner().clone()) + ) } // Check input note integrity and return the input note variables and the nullifier @@ -78,21 +75,11 @@ pub fn check_input_note( mut layouter: impl Layouter, advices: [Column; 10], instances: Column, - ecc_chip: EccChip, - sinsemilla_chip: SinsemillaChip< - NoteCommitmentHashDomain, - NoteCommitmentDomain, - TaigaFixedBases, - >, - note_commit_chip: NoteCommitmentChip, // PoseidonChip can not be cloned, use PoseidonConfig temporarily poseidon_config: PoseidonConfig, - // poseidon_chip: PoseidonChip, - add_chip: AddChip, input_note: Note, nf_row_idx: usize, ) -> Result { - // Check input note user integrity: address = Com_r(Com_r(nk, zero), app_data_dynamic) // Witness nk let nk = input_note.get_nk().unwrap(); let nk_var = assign_free_advice( @@ -121,13 +108,6 @@ pub fn check_input_note( Value::known(input_note.app_data_dynamic), )?; - // address = Com_r(app_data_dynamic, nk_com) - let address = poseidon_hash_gadget( - poseidon_config.clone(), - layouter.namespace(|| "address encoding"), - [app_data_dynamic.clone(), nk_com.clone()], - )?; - // Witness app_vk let app_vk = assign_free_advice( layouter.namespace(|| "witness app_vk"), @@ -178,41 +158,34 @@ pub fn check_input_note( )?; // Check note commitment - let cm = note_commitment_gadget( - layouter.namespace(|| "Hash NoteCommit pieces"), - sinsemilla_chip, - ecc_chip.clone(), - note_commit_chip, - address.clone(), + let cm = note_commitment_circuit( + layouter.namespace(|| "note commitment"), + poseidon_config.clone(), app_vk.clone(), app_data_static.clone(), + app_data_dynamic.clone(), + nk_com.clone(), rho.clone(), psi.clone(), value.clone(), - rcm.clone(), is_merkle_checked.clone(), + rcm.clone(), )?; // Generate nullifier - let poseidon_chip = PoseidonChip::construct(poseidon_config); let nf = nullifier_circuit( layouter.namespace(|| "Generate nullifier"), - poseidon_chip, - add_chip, - ecc_chip, + poseidon_config, nk_var, rho.clone(), psi.clone(), - &cm, + cm.clone(), )?; // Public nullifier layouter.constrain_instance(nf.cell(), instances, nf_row_idx)?; - let cm_x = cm.extract_p().inner().clone(); - let note_variables = NoteVariables { - address, app_vk, value, app_data_static, @@ -227,7 +200,7 @@ pub fn check_input_note( Ok(InputNoteVariables { note_variables, nf, - cm_x, + cm, }) } @@ -236,13 +209,6 @@ pub fn check_output_note( mut layouter: impl Layouter, advices: [Column; 10], instances: Column, - ecc_chip: EccChip, - sinsemilla_chip: SinsemillaChip< - NoteCommitmentHashDomain, - NoteCommitmentDomain, - TaigaFixedBases, - >, - note_commit_chip: NoteCommitmentChip, // PoseidonChip can not be cloned, use PoseidonConfig temporarily poseidon_config: PoseidonConfig, // poseidon_chip: PoseidonChip, @@ -264,13 +230,6 @@ pub fn check_output_note( Value::known(output_note.app_data_dynamic), )?; - // Check output note user integrity: address = Com_r(app_data_dynamic, nk_com) - let address = poseidon_hash_gadget( - poseidon_config, - layouter.namespace(|| "address encoding"), - [app_data_dynamic.clone(), nk_com.clone()], - )?; - // Witness app_vk let app_vk = assign_free_advice( layouter.namespace(|| "witness app_vk"), @@ -314,27 +273,24 @@ pub fn check_output_note( )?; // Check note commitment - let cm = note_commitment_gadget( - layouter.namespace(|| "Hash NoteCommit pieces"), - sinsemilla_chip, - ecc_chip, - note_commit_chip, - address.clone(), + let cm = note_commitment_circuit( + layouter.namespace(|| "note commitment"), + poseidon_config.clone(), app_vk.clone(), app_data_static.clone(), + app_data_dynamic.clone(), + nk_com.clone(), old_nf.clone(), psi.clone(), value.clone(), - rcm.clone(), is_merkle_checked.clone(), + rcm.clone(), )?; // Public cm - let cm_x = cm.extract_p().inner().clone(); - layouter.constrain_instance(cm_x.cell(), instances, cm_row_idx)?; + layouter.constrain_instance(cm.cell(), instances, cm_row_idx)?; let note_variables = NoteVariables { - address, app_vk, app_data_static, value, @@ -346,10 +302,7 @@ pub fn check_output_note( rcm, }; - Ok(OutputNoteVariables { - note_variables, - cm_x, - }) + Ok(OutputNoteVariables { note_variables, cm }) } pub fn derive_note_type( @@ -475,18 +428,11 @@ pub fn compute_value_commitment( #[test] fn test_halo2_nullifier_circuit() { - use crate::circuit::gadgets::add::AddConfig; use crate::circuit::gadgets::assign_free_advice; - use crate::constant::{NoteCommitmentDomain, NoteCommitmentHashDomain, TaigaFixedBases}; use crate::note::NoteCommitment; use crate::nullifier::{Nullifier, NullifierKeyContainer}; - use halo2_gadgets::{ - ecc::chip::EccConfig, - poseidon::{ - primitives as poseidon, Pow5Chip as PoseidonChip, Pow5Config as PoseidonConfig, - }, - sinsemilla::chip::{SinsemillaChip, SinsemillaConfig}, - utilities::lookup_range_check::LookupRangeCheckConfig, + use halo2_gadgets::poseidon::{ + primitives as poseidon, Pow5Chip as PoseidonChip, Pow5Config as PoseidonConfig, }; use halo2_proofs::{ arithmetic::Field, @@ -506,14 +452,7 @@ fn test_halo2_nullifier_circuit() { impl Circuit for MyCircuit { #[allow(clippy::type_complexity)] - type Config = ( - [Column; 10], - PoseidonConfig, - AddConfig, - EccConfig, - // add SinsemillaConfig to load look table, just for test - SinsemillaConfig, - ); + type Config = ([Column; 10], PoseidonConfig); type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { @@ -549,17 +488,9 @@ fn test_halo2_nullifier_circuit() { meta.fixed_column(), ]; - let table_idx = meta.lookup_table_column(); - let lookup = ( - table_idx, - meta.lookup_table_column(), - meta.lookup_table_column(), - ); - let constants = meta.fixed_column(); meta.enable_constant(constants); - let range_check = LookupRangeCheckConfig::configure(meta, advices[9], table_idx); let poseidon_config = PoseidonChip::configure::( meta, advices[6..9].try_into().unwrap(), @@ -567,30 +498,7 @@ fn test_halo2_nullifier_circuit() { lagrange_coeffs[2..5].try_into().unwrap(), lagrange_coeffs[5..8].try_into().unwrap(), ); - - let add_config = AddChip::configure(meta, advices[0..2].try_into().unwrap()); - - let ecc_config = - EccChip::::configure(meta, advices, lagrange_coeffs, range_check); - let sinsemilla_config = SinsemillaChip::< - NoteCommitmentHashDomain, - NoteCommitmentDomain, - TaigaFixedBases, - >::configure( - meta, - advices[..5].try_into().unwrap(), - advices[2], - lagrange_coeffs[0], - lookup, - range_check, - ); - ( - advices, - poseidon_config, - add_config, - ecc_config, - sinsemilla_config, - ) + (advices, poseidon_config) } fn synthesize( @@ -598,16 +506,7 @@ fn test_halo2_nullifier_circuit() { config: Self::Config, mut layouter: impl Layouter, ) -> Result<(), Error> { - let (advices, poseidon_config, add_config, ecc_config, sinsemilla_config) = config; - let poseidon_chip = PoseidonChip::construct(poseidon_config); - let ecc_chip = EccChip::construct(ecc_config); - let add_chip = AddChip::::construct(add_config, ()); - SinsemillaChip::< - NoteCommitmentHashDomain, - NoteCommitmentDomain, - TaigaFixedBases, - >::load(sinsemilla_config, &mut layouter)?; - + let (advices, poseidon_config) = config; // Witness nk let nk = assign_free_advice( layouter.namespace(|| "witness nk"), @@ -630,21 +529,19 @@ fn test_halo2_nullifier_circuit() { )?; // Witness cm - let cm = Point::new( - ecc_chip.clone(), + let cm = assign_free_advice( layouter.namespace(|| "witness cm"), - Value::known(self.cm.inner().to_affine()), + advices[0], + Value::known(self.cm.inner()), )?; let nf = nullifier_circuit( layouter.namespace(|| "nullifier"), - poseidon_chip, - add_chip, - ecc_chip, + poseidon_config, nk, rho, psi, - &cm, + cm, )?; let expect_nf = { diff --git a/taiga_halo2/src/circuit/mod.rs b/taiga_halo2/src/circuit/mod.rs index 9e791a94..ddeab568 100644 --- a/taiga_halo2/src/circuit/mod.rs +++ b/taiga_halo2/src/circuit/mod.rs @@ -2,7 +2,7 @@ pub mod action_circuit; pub mod gadgets; pub mod integrity; pub mod merkle_circuit; -pub mod note_circuit; +// pub mod note_circuit; #[macro_use] pub mod vp_circuit; pub mod blake2s; diff --git a/taiga_halo2/src/circuit/note_circuit.rs b/taiga_halo2/src/circuit/note_circuit.rs deleted file mode 100644 index d7f748c3..00000000 --- a/taiga_halo2/src/circuit/note_circuit.rs +++ /dev/null @@ -1,958 +0,0 @@ -use crate::circuit::gadgets::add::{AddChip, AddConfig}; -use crate::constant::{ - BaseFieldGenerators, NoteCommitmentDomain, NoteCommitmentHashDomain, TaigaFixedBases, -}; -use halo2_gadgets::{ - ecc::chip::EccConfig, - ecc::{chip::EccChip, FixedPointBaseField, Point}, - poseidon::{primitives as poseidon, Pow5Chip as PoseidonChip, Pow5Config as PoseidonConfig}, - sinsemilla::{ - chip::{SinsemillaChip, SinsemillaConfig}, - CommitDomains, HashDomain, Message, MessagePiece, - }, - utilities::{bool_check, lookup_range_check::LookupRangeCheckConfig, RangeConstrained}, -}; -use halo2_proofs::{ - circuit::{AssignedCell, Chip, Layouter}, - plonk::{Advice, Column, ConstraintSystem, Constraints, Error, Instance, Selector}, - poly::Rotation, -}; -use pasta_curves::group::ff::PrimeField; -use pasta_curves::pallas; - -type NoteCommitPiece = MessagePiece< - pallas::Affine, - SinsemillaChip, - 10, - 253, ->; - -/// bit10 = (bits 250..=255) || (bits 0..=4) -/// -/// | A_6 | A_7 | A_8 | q_notecommit_5_5 | -/// ------------------------------------ -/// | bit10 | bit5 | bit5_2 | 1 | -/// -#[derive(Clone, Debug)] -struct Decompose5_5 { - q_notecommit_5_5: Selector, - col_l: Column, - col_m: Column, - col_r: Column, -} - -impl Decompose5_5 { - fn configure( - meta: &mut ConstraintSystem, - col_l: Column, - col_m: Column, - col_r: Column, - two_pow_5: pallas::Base, - ) -> Self { - let q_notecommit_5_5 = meta.selector(); - - meta.create_gate("NoteCommit MessagePiece bit10", |meta| { - let q_notecommit_5_5 = meta.query_selector(q_notecommit_5_5); - - // bit10 has been constrained to 10 bits by the Sinsemilla hash. - let bit10 = meta.query_advice(col_l, Rotation::cur()); - // bit5 has been constrained to 5 bits outside this gate. - let bit5 = meta.query_advice(col_m, Rotation::cur()); - // bit5_2 has been constrained to 5 bits outside this gate. - let bit5_2 = meta.query_advice(col_r, Rotation::cur()); - - // bit10 = bit5 + (2^5) bit5_2 - let decomposition_check = bit10 - (bit5 + bit5_2 * two_pow_5); - - Constraints::with_selector( - q_notecommit_5_5, - Some(("decomposition", decomposition_check)), - ) - }); - - Self { - q_notecommit_5_5, - col_l, - col_m, - col_r, - } - } - - #[allow(clippy::type_complexity)] - fn decompose( - lookup_config: &LookupRangeCheckConfig, - chip: SinsemillaChip, - layouter: &mut impl Layouter, - first: &AssignedCell, - second: &AssignedCell, - ) -> Result< - ( - NoteCommitPiece, - RangeConstrained>, - RangeConstrained>, - ), - Error, - > { - // Constrain bit5 to be 5 bits. - let bit5 = RangeConstrained::witness_short( - lookup_config, - layouter.namespace(|| "bit5"), - first.value(), - 250..255, - )?; - - // Constrain bit5_2 to be 5 bits. - let bit5_2 = RangeConstrained::witness_short( - lookup_config, - layouter.namespace(|| "bit5_2"), - second.value(), - 0..5, - )?; - - let bit10 = MessagePiece::from_subpieces( - chip, - layouter.namespace(|| "bit10"), - [bit5.value(), bit5_2.value()], - )?; - - Ok((bit10, bit5, bit5_2)) - } - - fn assign( - &self, - layouter: &mut impl Layouter, - bit10: NoteCommitPiece, - bit5: RangeConstrained>, - bit5_2: RangeConstrained>, - ) -> Result<(), Error> { - layouter.assign_region( - || "NoteCommit MessagePiece bit10", - |mut region| { - self.q_notecommit_5_5.enable(&mut region, 0)?; - - bit10 - .inner() - .cell_value() - .copy_advice(|| "bit10", &mut region, self.col_l, 0)?; - bit5.inner() - .copy_advice(|| "bit5", &mut region, self.col_m, 0)?; - bit5_2 - .inner() - .copy_advice(|| "bit5_2", &mut region, self.col_r, 0)?; - - Ok(()) - }, - ) - } -} - -/// bit10 = (bits 250..=255) || (1 bit) || (bits 64) -/// -/// | A_6 | A_7 |q_notecommit_5_1_64 | -/// ------------------------------------ -/// | bit70 | bit5 | 1 | -/// | bit1 | bit64 | 0 | -/// -#[derive(Clone, Debug)] -struct Decompose5_1_64 { - q_notecommit_5_1_64: Selector, - col_l: Column, - col_m: Column, -} - -impl Decompose5_1_64 { - fn configure( - meta: &mut ConstraintSystem, - col_l: Column, - col_m: Column, - two_pow_5: pallas::Base, - two_pow_6: pallas::Base, - ) -> Self { - let q_notecommit_5_1_64 = meta.selector(); - - meta.create_gate("NoteCommit MessagePiece bit70", |meta| { - let q_notecommit_5_1_64 = meta.query_selector(q_notecommit_5_1_64); - - // bit70 has been constrained to 70 bits by the Sinsemilla hash. - let bit70 = meta.query_advice(col_l, Rotation::cur()); - // bit5 has been constrained to 5 bits outside this gate. - let bit5 = meta.query_advice(col_m, Rotation::cur()); - // bit1 has been constrained to 1 bit outside this gate. - let bit1 = meta.query_advice(col_l, Rotation::next()); - // bit64 has been constrained to 64 bits outside this gate. - let bit64 = meta.query_advice(col_m, Rotation::next()); - - // bit10 = bit5 + (2^5) * bit1 + (2^6) * bit64 - let decomposition_check = bit70 - (bit5 + bit1.clone() * two_pow_5 + bit64 * two_pow_6); - - Constraints::with_selector( - q_notecommit_5_1_64, - [ - ("bool_check is_merkle_checked bit", bool_check(bit1)), - ("decomposition", decomposition_check), - ], - ) - }); - - Self { - q_notecommit_5_1_64, - col_l, - col_m, - } - } - - #[allow(clippy::type_complexity)] - fn decompose( - lookup_config: &LookupRangeCheckConfig, - chip: SinsemillaChip, - layouter: &mut impl Layouter, - first: &AssignedCell, - is_merkle_checked: &AssignedCell, - value: &AssignedCell, - ) -> Result< - ( - NoteCommitPiece, - RangeConstrained>, - ), - Error, - > { - // Constrain bit5 to be 5 bits. - let bit5 = RangeConstrained::witness_short( - lookup_config, - layouter.namespace(|| "bit5"), - first.value(), - 250..255, - )?; - - // bit1 is the boolean_constrained is_merkle_checked - let bit1 = RangeConstrained::bitrange_of(is_merkle_checked.value(), 0..1); - - let bit64 = RangeConstrained::bitrange_of(value.value(), 0..64); - - let bit70 = MessagePiece::from_subpieces( - chip, - layouter.namespace(|| "bit70"), - [bit5.value(), bit1, bit64], - )?; - - Ok((bit70, bit5)) - } - - fn assign( - &self, - layouter: &mut impl Layouter, - bit70: NoteCommitPiece, - bit5: RangeConstrained>, - is_merkle_checked: AssignedCell, - value: AssignedCell, - ) -> Result<(), Error> { - layouter.assign_region( - || "NoteCommit MessagePiece bit70", - |mut region| { - self.q_notecommit_5_1_64.enable(&mut region, 0)?; - - bit70 - .inner() - .cell_value() - .copy_advice(|| "bit70", &mut region, self.col_l, 0)?; - bit5.inner() - .copy_advice(|| "bit5", &mut region, self.col_m, 0)?; - is_merkle_checked.copy_advice( - || "is_merkle_checked bit1", - &mut region, - self.col_l, - 1, - )?; - value.copy_advice(|| "value 64bit", &mut region, self.col_m, 1)?; - Ok(()) - }, - ) - } -} - -/// | A_6 | A_7 | A_8 | q_base_250_5 | -/// ------------------------------------------------ -/// | v | v_250 | v_5 | 1 | -/// -#[derive(Clone, Debug)] -struct BaseCanonicity250_5 { - q_base_250_5: Selector, - col_l: Column, - col_m: Column, - col_r: Column, -} - -impl BaseCanonicity250_5 { - fn configure( - meta: &mut ConstraintSystem, - col_l: Column, - col_m: Column, - col_r: Column, - two_pow_250: pallas::Base, - ) -> Self { - let q_base_250_5 = meta.selector(); - - meta.create_gate("NoteCommit input value", |meta| { - let q_base_250_5 = meta.query_selector(q_base_250_5); - - let value = meta.query_advice(col_l, Rotation::cur()); - // v_250 has been constrained to 250 bits. - let v_250 = meta.query_advice(col_m, Rotation::cur()); - // v_5 has been constrained to 5 bits. - let v_5 = meta.query_advice(col_r, Rotation::cur()); - - // value = v_250 + (2^250)v_5 - let value_check = v_250 + v_5 * two_pow_250 - value; - - Constraints::with_selector(q_base_250_5, Some(("value_check", value_check))) - }); - - Self { - q_base_250_5, - col_l, - col_m, - col_r, - } - } - - fn assign( - &self, - layouter: &mut impl Layouter, - value: AssignedCell, - v_250: NoteCommitPiece, - v_5: RangeConstrained>, - ) -> Result<(), Error> { - layouter.assign_region( - || "NoteCommit input value", - |mut region| { - value.copy_advice(|| "value", &mut region, self.col_l, 0)?; - v_250 - .inner() - .cell_value() - .copy_advice(|| "v_250", &mut region, self.col_m, 0)?; - v_5.inner() - .copy_advice(|| "v_5", &mut region, self.col_r, 0)?; - self.q_base_250_5.enable(&mut region, 0) - }, - ) - } -} - -/// | A_6 | A_7 | A_8 | q_base_250_5 | -/// ------------------------------------------------ -/// | v | v_tail | v_5 | 1 | -/// -#[derive(Clone, Debug)] -struct BaseCanonicity5 { - q_base_5: Selector, - col_l: Column, - col_m: Column, - col_r: Column, -} - -impl BaseCanonicity5 { - fn configure( - meta: &mut ConstraintSystem, - col_l: Column, - col_m: Column, - col_r: Column, - two_pow_5: pallas::Base, - ) -> Self { - let q_base_5 = meta.selector(); - - meta.create_gate("NoteCommit input value", |meta| { - let q_base_5 = meta.query_selector(q_base_5); - - let value = meta.query_advice(col_l, Rotation::cur()); - // v_tail has been constrained to the tail bits. - let v_tail = meta.query_advice(col_m, Rotation::cur()); - // v_5 has been constrained to the previous 5 bits. - let v_5 = meta.query_advice(col_r, Rotation::cur()); - - // value = v_tail * (2^5) + v_5 - let value_check = v_tail * two_pow_5 + v_5 - value; - - Constraints::with_selector(q_base_5, Some(("value_check", value_check))) - }); - - Self { - q_base_5, - col_l, - col_m, - col_r, - } - } - - fn assign( - &self, - layouter: &mut impl Layouter, - value: AssignedCell, - v_tail: NoteCommitPiece, - v_5: RangeConstrained>, - ) -> Result<(), Error> { - layouter.assign_region( - || "NoteCommit input value", - |mut region| { - value.copy_advice(|| "value", &mut region, self.col_l, 0)?; - v_tail - .inner() - .cell_value() - .copy_advice(|| "v_tail", &mut region, self.col_m, 0)?; - v_5.inner() - .copy_advice(|| "v_5", &mut region, self.col_r, 0)?; - self.q_base_5.enable(&mut region, 0) - }, - ) - } -} - -#[derive(Clone, Debug)] -pub struct NoteCommitmentConfig { - advices: [Column; 10], - decompose5_5: Decompose5_5, - decompose5_1_64: Decompose5_1_64, - base_canonicity_250_5: BaseCanonicity250_5, - base_canonicity_5: BaseCanonicity5, - pub sinsemilla_config: - SinsemillaConfig, -} - -#[derive(Clone, Debug)] -pub struct NoteCommitmentChip { - config: NoteCommitmentConfig, -} - -impl NoteCommitmentChip { - pub fn configure( - meta: &mut ConstraintSystem, - advices: [Column; 10], - sinsemilla_config: SinsemillaConfig< - NoteCommitmentHashDomain, - NoteCommitmentDomain, - TaigaFixedBases, - >, - ) -> NoteCommitmentConfig { - let two_pow_5 = pallas::Base::from(1 << 5); - let two_pow_6 = pallas::Base::from(1 << 6); - let two_pow_250 = pallas::Base::from_u128(1 << 125).square(); - - let col_l = advices[6]; - let col_m = advices[7]; - let col_r = advices[8]; - - // Decompose5_5 configure - let decompose5_5 = Decompose5_5::configure(meta, col_l, col_m, col_r, two_pow_5); - - // Decompose5_1_64 configure - let decompose5_1_64 = Decompose5_1_64::configure(meta, col_l, col_m, two_pow_5, two_pow_6); - - // Base canonicity configure - let base_canonicity_250_5 = - BaseCanonicity250_5::configure(meta, col_l, col_m, col_r, two_pow_250); - let base_canonicity_5 = BaseCanonicity5::configure(meta, col_l, col_m, col_r, two_pow_5); - - NoteCommitmentConfig { - decompose5_5, - decompose5_1_64, - base_canonicity_250_5, - base_canonicity_5, - advices, - sinsemilla_config, - } - } - - pub fn construct(config: NoteCommitmentConfig) -> Self { - Self { config } - } -} - -#[allow(clippy::too_many_arguments)] -pub fn note_commitment_gadget( - mut layouter: impl Layouter, - chip: SinsemillaChip, - ecc_chip: EccChip, - note_commit_chip: NoteCommitmentChip, - address: AssignedCell, - app_vp: AssignedCell, - app_data_static: AssignedCell, - rho: AssignedCell, - psi: AssignedCell, - value: AssignedCell, - rcm: AssignedCell, - is_merkle_checked: AssignedCell, -) -> Result>, Error> { - let lookup_config = chip.config().lookup_config(); - - // `user_0_249` = bits 0..=249 of `address` - let user_0_249 = MessagePiece::from_subpieces( - chip.clone(), - layouter.namespace(|| "user_0_249"), - [RangeConstrained::bitrange_of(address.value(), 0..250)], - )?; - - // `a` = (bits 250..=255 of user) || (bits 0..=4 of application) - let (a, user_tail_bit5, app_pre_bit5) = Decompose5_5::decompose( - &lookup_config, - chip.clone(), - &mut layouter, - &address, - &app_vp, - )?; - - // `app_5_254` = bits 5..=254 of `application` - let app_5_254 = MessagePiece::from_subpieces( - chip.clone(), - layouter.namespace(|| "app_5_254"), - [RangeConstrained::bitrange_of(app_vp.value(), 5..255)], - )?; - - // `data_0_249` = bits 0..=249 of `app_data_static` - let data_0_249 = MessagePiece::from_subpieces( - chip.clone(), - layouter.namespace(|| "data_0_249"), - [RangeConstrained::bitrange_of( - app_data_static.value(), - 0..250, - )], - )?; - - // b = (bits 250..=255 of app_data_static) || (bits 0..=4 of rho) - let (b, data_tail_bit5, rho_pre_bit5) = Decompose5_5::decompose( - &lookup_config, - chip.clone(), - &mut layouter, - &app_data_static, - &rho, - )?; - - // `rho_5_254` = bits 5..=254 of `rho` - let rho_5_254 = MessagePiece::from_subpieces( - chip.clone(), - layouter.namespace(|| "rho_5_254"), - [RangeConstrained::bitrange_of(rho.value(), 5..255)], - )?; - - // `psi_0_249` = bits 0..=249 of `psi` - let psi_0_249 = MessagePiece::from_subpieces( - chip.clone(), - layouter.namespace(|| "psi_0_249"), - [RangeConstrained::bitrange_of(psi.value(), 0..250)], - )?; - - // `c` = (bits 250..=255 of psi) || (is_merkle_checked bit) || (64 bits of value) - let (c, psi_tail_bit5) = Decompose5_1_64::decompose( - &lookup_config, - chip.clone(), - &mut layouter, - &psi, - &is_merkle_checked, - &value, - )?; - - // cm = NoteCommit^rcm(address || app_vp || app_data_static || rho || psi || is_merkle_checked || value) - let cm = { - let message = Message::from_pieces( - chip.clone(), - vec![ - user_0_249.clone(), - a.clone(), - app_5_254.clone(), - data_0_249.clone(), - b.clone(), - rho_5_254.clone(), - psi_0_249.clone(), - c.clone(), - ], - ); - let hash_domain = - HashDomain::new(chip, ecc_chip.clone(), &NoteCommitmentDomain.hash_domain()); - let (p, _) = hash_domain.hash_to_point(layouter.namespace(|| "hash to point"), message)?; - let blind_base = - FixedPointBaseField::from_inner(ecc_chip, BaseFieldGenerators::NoteCommitmentR); - let blind = blind_base.mul(layouter.namespace(|| "[r] R"), rcm)?; - p.add(layouter.namespace(|| "M + [r] R"), &blind)? - }; - - // assign values - let cfg = note_commit_chip.config; - - cfg.decompose5_5.assign( - &mut layouter, - a, - user_tail_bit5.clone(), - app_pre_bit5.clone(), - )?; - - cfg.decompose5_5.assign( - &mut layouter, - b, - data_tail_bit5.clone(), - rho_pre_bit5.clone(), - )?; - - cfg.decompose5_1_64.assign( - &mut layouter, - c, - psi_tail_bit5.clone(), - is_merkle_checked, - value, - )?; - - cfg.base_canonicity_250_5 - .assign(&mut layouter, address, user_0_249, user_tail_bit5)?; - cfg.base_canonicity_5 - .assign(&mut layouter, app_vp, app_5_254, app_pre_bit5)?; - cfg.base_canonicity_250_5 - .assign(&mut layouter, app_data_static, data_0_249, data_tail_bit5)?; - cfg.base_canonicity_5 - .assign(&mut layouter, rho, rho_5_254, rho_pre_bit5)?; - cfg.base_canonicity_250_5 - .assign(&mut layouter, psi, psi_0_249, psi_tail_bit5)?; - - Ok(cm) -} - -#[derive(Clone, Debug)] -pub struct NoteConfig { - pub instances: Column, - pub advices: [Column; 10], - pub add_config: AddConfig, - pub ecc_config: EccConfig, - pub poseidon_config: PoseidonConfig, - pub sinsemilla_config: - SinsemillaConfig, - pub note_commit_config: NoteCommitmentConfig, -} - -#[derive(Clone, Debug)] -pub struct NoteChip { - config: NoteConfig, -} - -impl NoteChip { - pub fn configure( - meta: &mut ConstraintSystem, - instances: Column, - advices: [Column; 10], - ) -> NoteConfig { - let add_config = AddChip::configure(meta, advices[0..2].try_into().unwrap()); - - let table_idx = meta.lookup_table_column(); - let lookup = ( - table_idx, - meta.lookup_table_column(), - meta.lookup_table_column(), - ); - - let range_check = LookupRangeCheckConfig::configure(meta, advices[9], table_idx); - - let lagrange_coeffs = [ - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - ]; - meta.enable_constant(lagrange_coeffs[0]); - - let ecc_config = - EccChip::::configure(meta, advices, lagrange_coeffs, range_check); - - let poseidon_config = PoseidonChip::configure::( - meta, - advices[6..9].try_into().unwrap(), - advices[5], - lagrange_coeffs[2..5].try_into().unwrap(), - lagrange_coeffs[5..8].try_into().unwrap(), - ); - - let sinsemilla_config = SinsemillaChip::< - NoteCommitmentHashDomain, - NoteCommitmentDomain, - TaigaFixedBases, - >::configure( - meta, - advices[..5].try_into().unwrap(), - advices[2], - lagrange_coeffs[0], - lookup, - range_check, - ); - - let note_commit_config = - NoteCommitmentChip::configure(meta, advices, sinsemilla_config.clone()); - - NoteConfig { - instances, - advices, - add_config, - ecc_config, - poseidon_config, - sinsemilla_config, - note_commit_config, - } - } - - pub fn construct(config: NoteConfig) -> Self { - Self { config } - } -} - -#[test] -fn test_halo2_note_commitment_circuit() { - use crate::circuit::gadgets::assign_free_advice; - use crate::note::{Note, RandomSeed}; - use crate::nullifier::{Nullifier, NullifierKeyContainer}; - use halo2_gadgets::{ - ecc::{ - chip::{EccChip, EccConfig}, - NonIdentityPoint, - }, - sinsemilla::chip::SinsemillaChip, - utilities::lookup_range_check::LookupRangeCheckConfig, - }; - use halo2_proofs::{ - arithmetic::Field, - circuit::{Layouter, SimpleFloorPlanner, Value}, - dev::MockProver, - plonk::{Circuit, ConstraintSystem, Error}, - }; - use pasta_curves::group::Curve; - use rand::{rngs::OsRng, RngCore}; - - #[derive(Default)] - struct MyCircuit { - app_vk: pallas::Base, - app_data_static: pallas::Base, - app_data_dynamic: pallas::Base, - value: u64, - nk: NullifierKeyContainer, - rho: Nullifier, - is_merkle_checked: bool, - rseed: RandomSeed, - } - - impl Circuit for MyCircuit { - type Config = (NoteCommitmentConfig, EccConfig); - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - Self::default() - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let advices = [ - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - ]; - - // Shared fixed column for loading constants. - let constants = meta.fixed_column(); - meta.enable_constant(constants); - - for advice in advices.iter() { - meta.enable_equality(*advice); - } - - let table_idx = meta.lookup_table_column(); - let lookup = ( - table_idx, - meta.lookup_table_column(), - meta.lookup_table_column(), - ); - let lagrange_coeffs = [ - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - ]; - - let range_check = LookupRangeCheckConfig::configure(meta, advices[9], table_idx); - let sinsemilla_config = SinsemillaChip::< - NoteCommitmentHashDomain, - NoteCommitmentDomain, - TaigaFixedBases, - >::configure( - meta, - advices[..5].try_into().unwrap(), - advices[2], - lagrange_coeffs[0], - lookup, - range_check, - ); - let note_commit_config = - NoteCommitmentChip::configure(meta, advices, sinsemilla_config); - - let ecc_config = - EccChip::::configure(meta, advices, lagrange_coeffs, range_check); - - (note_commit_config, ecc_config) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let (note_commit_config, ecc_config) = config; - - // Load the Sinsemilla generator lookup table used by the whole circuit. - SinsemillaChip::< - NoteCommitmentHashDomain, - NoteCommitmentDomain, - TaigaFixedBases, - >::load(note_commit_config.sinsemilla_config.clone(), &mut layouter)?; - let note = Note::new( - self.app_vk, - self.app_data_static, - self.app_data_dynamic, - self.value, - self.nk, - self.rho, - self.is_merkle_checked, - self.rseed, - ); - // Construct a Sinsemilla chip - let sinsemilla_chip = - SinsemillaChip::construct(note_commit_config.sinsemilla_config.clone()); - - // Construct an ECC chip - let ecc_chip = EccChip::construct(ecc_config); - - // Construct a NoteCommit chip - let note_commit_chip = NoteCommitmentChip::construct(note_commit_config.clone()); - - // Witness user - let address = assign_free_advice( - layouter.namespace(|| "witness address"), - note_commit_config.advices[0], - Value::known(note.get_address()), - )?; - - // Witness app_vk - let app_vp = assign_free_advice( - layouter.namespace(|| "witness app_vk"), - note_commit_config.advices[0], - Value::known(note.get_app_vk()), - )?; - - // Witness app_data_static - let app_data_static = assign_free_advice( - layouter.namespace(|| "witness app_data_static"), - note_commit_config.advices[0], - Value::known(note.get_app_data_static()), - )?; - - // Witness a random non-negative u64 note value - // A note value cannot be negative. - let value_var = { - assign_free_advice( - layouter.namespace(|| "witness value"), - note_commit_config.advices[0], - Value::known(pallas::Base::from(note.value)), - )? - }; - - // Witness rho - let rho = assign_free_advice( - layouter.namespace(|| "witness rho"), - note_commit_config.advices[0], - Value::known(note.rho.inner()), - )?; - - // Witness psi - let psi = assign_free_advice( - layouter.namespace(|| "witness psi"), - note_commit_config.advices[0], - Value::known(note.get_psi()), - )?; - - let rcm = assign_free_advice( - layouter.namespace(|| "witness rcm"), - note_commit_config.advices[0], - Value::known(note.get_rcm()), - )?; - - let is_normail_var = assign_free_advice( - layouter.namespace(|| "witness is_merkle_checked"), - note_commit_config.advices[0], - Value::known(pallas::Base::from(note.is_merkle_checked)), - )?; - - let cm = note_commitment_gadget( - layouter.namespace(|| "Hash NoteCommit pieces"), - sinsemilla_chip, - ecc_chip.clone(), - note_commit_chip, - address, - app_vp, - app_data_static, - rho, - psi, - value_var, - rcm, - is_normail_var, - )?; - let expected_cm = { - let point = note.commitment().inner().to_affine(); - NonIdentityPoint::new( - ecc_chip, - layouter.namespace(|| "witness cm"), - Value::known(point), - )? - }; - cm.constrain_equal(layouter.namespace(|| "cm == expected cm"), &expected_cm) - } - } - - let mut rng = OsRng; - - // Test note with flase is_merkle_checked flag - { - let circuit = MyCircuit { - app_vk: pallas::Base::random(&mut rng), - app_data_static: pallas::Base::random(&mut rng), - app_data_dynamic: pallas::Base::random(&mut rng), - value: rng.next_u64(), - nk: NullifierKeyContainer::random_key(&mut rng), - rho: Nullifier::default(), - is_merkle_checked: false, - rseed: RandomSeed::random(&mut rng), - }; - - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } - - // Test note with true is_merkle_checked flag - { - let circuit = MyCircuit { - app_vk: pallas::Base::random(&mut rng), - app_data_static: pallas::Base::random(&mut rng), - app_data_dynamic: pallas::Base::random(&mut rng), - value: rng.next_u64(), - nk: NullifierKeyContainer::random_key(&mut rng), - rho: Nullifier::default(), - is_merkle_checked: true, - rseed: RandomSeed::random(&mut rng), - }; - - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } -} diff --git a/taiga_halo2/src/circuit/vp_circuit.rs b/taiga_halo2/src/circuit/vp_circuit.rs index 106fb294..7a3af678 100644 --- a/taiga_halo2/src/circuit/vp_circuit.rs +++ b/taiga_halo2/src/circuit/vp_circuit.rs @@ -14,11 +14,9 @@ use crate::{ target_note_variable::{GetIsInputNoteFlagConfig, GetOwnedNoteVariableConfig}, }, integrity::{check_input_note, check_output_note}, - note_circuit::{NoteChip, NoteCommitmentChip, NoteConfig}, }, constant::{ - NoteCommitmentDomain, NoteCommitmentHashDomain, TaigaFixedBases, - NOTE_ENCRYPTION_CIPHERTEXT_NUM, NUM_NOTE, SETUP_PARAMS_MAP, + TaigaFixedBases, NOTE_ENCRYPTION_CIPHERTEXT_NUM, NUM_NOTE, SETUP_PARAMS_MAP, VP_CIRCUIT_NOTE_ENCRYPTION_PK_X_IDX, VP_CIRCUIT_NOTE_ENCRYPTION_PK_Y_IDX, VP_CIRCUIT_NOTE_ENCRYPTION_PUBLIC_INPUT_BEGIN_IDX, VP_CIRCUIT_NULLIFIER_ONE_PUBLIC_INPUT_IDX, VP_CIRCUIT_NULLIFIER_TWO_PUBLIC_INPUT_IDX, @@ -35,13 +33,18 @@ use crate::{ use dyn_clone::{clone_trait_object, DynClone}; //use ff::PrimeField; use group::cofactor::CofactorCurveAffine; -use halo2_gadgets::{ecc::chip::EccChip, sinsemilla::chip::SinsemillaChip}; +use halo2_gadgets::{ + ecc::chip::EccChip, + ecc::chip::EccConfig, + poseidon::{primitives as poseidon, Pow5Chip as PoseidonChip, Pow5Config as PoseidonConfig}, + utilities::lookup_range_check::LookupRangeCheckConfig, +}; use halo2_proofs::{ arithmetic::CurveAffine, circuit::{AssignedCell, Layouter, Value}, plonk::{ keygen_pk, keygen_vk, Advice, Circuit, Column, ConstraintSystem, Error, Instance, - VerifyingKey, + TableColumn, VerifyingKey, }, poly::commitment::Params, }; @@ -305,9 +308,11 @@ impl From> for ValidityPredicatePublicInputs { #[derive(Clone, Debug)] pub struct ValidityPredicateConfig { - pub note_conifg: NoteConfig, pub advices: [Column; 10], pub instances: Column, + pub table_idx: TableColumn, + pub ecc_config: EccConfig, + pub poseidon_config: PoseidonConfig, pub get_is_input_note_flag_config: GetIsInputNoteFlagConfig, pub get_owned_note_variable_config: GetOwnedNoteVariableConfig, pub conditional_equal_config: ConditionalEqualConfig, @@ -341,7 +346,32 @@ impl ValidityPredicateConfig { meta.enable_equality(*advice); } - let note_conifg = NoteChip::configure(meta, instances, advices); + let table_idx = meta.lookup_table_column(); + + let range_check = LookupRangeCheckConfig::configure(meta, advices[9], table_idx); + + let lagrange_coeffs = [ + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + ]; + meta.enable_constant(lagrange_coeffs[0]); + + let ecc_config = + EccChip::::configure(meta, advices, lagrange_coeffs, range_check); + + let poseidon_config = PoseidonChip::configure::( + meta, + advices[6..9].try_into().unwrap(), + advices[5], + lagrange_coeffs[2..5].try_into().unwrap(), + lagrange_coeffs[5..8].try_into().unwrap(), + ); let get_owned_note_variable_config = GetOwnedNoteVariableConfig::configure( meta, @@ -357,7 +387,7 @@ impl ValidityPredicateConfig { let conditional_select_config = ConditionalSelectConfig::configure(meta, [advices[0], advices[1]]); - let add_config = note_conifg.add_config.clone(); + let add_config = AddChip::configure(meta, [advices[0], advices[1]]); let sub_config = SubChip::configure(meta, [advices[0], advices[1]]); let mul_config = MulChip::configure(meta, [advices[0], advices[1]]); @@ -365,9 +395,11 @@ impl ValidityPredicateConfig { ExtendedOrRelationConfig::configure(meta, [advices[0], advices[1], advices[2]]); let blake2s_config = Blake2sConfig::configure(meta, advices); Self { - note_conifg, advices, instances, + table_idx, + ecc_config, + poseidon_config, get_is_input_note_flag_config, get_owned_note_variable_config, conditional_equal_config, @@ -396,26 +428,21 @@ pub trait ValidityPredicateCircuit: Circuit + ValidityPredicateVer config: ValidityPredicateConfig, mut layouter: impl Layouter, ) -> Result { - let note_config = config.note_conifg; - // Load the Sinsemilla generator lookup table used by the whole circuit. - SinsemillaChip::::load( - note_config.sinsemilla_config.clone(), - &mut layouter, + layouter.assign_table( + || "table_idx", + |mut table| { + for index in 0..(1 << 10) { + table.assign_cell( + || "table_idx", + config.table_idx, + index, + || Value::known(pallas::Base::from(index as u64)), + )?; + } + Ok(()) + }, )?; - // Construct a Sinsemilla chip - let sinsemilla_chip = SinsemillaChip::construct(note_config.sinsemilla_config.clone()); - - // Construct an ECC chip - let ecc_chip = EccChip::construct(note_config.ecc_config); - - // Construct a NoteCommit chip - let note_commit_chip = - NoteCommitmentChip::construct(note_config.note_commit_config.clone()); - - // Construct an add chip - let add_chip = AddChip::::construct(note_config.add_config, ()); - let input_notes = self.get_input_notes(); let output_notes = self.get_output_notes(); let mut input_note_variables = vec![]; @@ -423,13 +450,9 @@ pub trait ValidityPredicateCircuit: Circuit + ValidityPredicateVer for i in 0..NUM_NOTE { input_note_variables.push(check_input_note( layouter.namespace(|| "check input note"), - note_config.advices, - note_config.instances, - ecc_chip.clone(), - sinsemilla_chip.clone(), - note_commit_chip.clone(), - note_config.poseidon_config.clone(), - add_chip.clone(), + config.advices, + config.instances, + config.poseidon_config.clone(), input_notes[i], i * 2, )?); @@ -437,17 +460,14 @@ pub trait ValidityPredicateCircuit: Circuit + ValidityPredicateVer // The old_nf may not be from above input note let old_nf = assign_free_advice( layouter.namespace(|| "old nf"), - note_config.advices[0], + config.advices[0], Value::known(output_notes[i].rho.inner()), )?; output_note_variables.push(check_output_note( layouter.namespace(|| "check output note"), - note_config.advices, - note_config.instances, - ecc_chip.clone(), - sinsemilla_chip.clone(), - note_commit_chip.clone(), - note_config.poseidon_config.clone(), + config.advices, + config.instances, + config.poseidon_config.clone(), output_notes[i], old_nf, i * 2 + 1, @@ -457,12 +477,12 @@ pub trait ValidityPredicateCircuit: Circuit + ValidityPredicateVer // Publicize the owned_note_pub_id let owned_note_pub_id = assign_free_advice( layouter.namespace(|| "owned_note_pub_id"), - note_config.advices[0], + config.advices[0], Value::known(self.get_owned_note_pub_id()), )?; layouter.constrain_instance( owned_note_pub_id.cell(), - note_config.instances, + config.instances, VP_CIRCUIT_OWNED_NOTE_PUB_ID_PUBLIC_INPUT_IDX, )?; @@ -503,7 +523,7 @@ pub trait ValidityPredicateCircuit: Circuit + ValidityPredicateVer let nf = input_note.get_nf().unwrap().inner(); public_inputs.push(nf); let cm = output_note.commitment(); - public_inputs.push(cm.get_x()); + public_inputs.push(cm.inner()); }); public_inputs.push(self.get_owned_note_pub_id()); public_inputs @@ -528,7 +548,6 @@ pub struct BasicValidityPredicateVariables { #[derive(Debug, Clone)] pub struct NoteVariables { - pub address: AssignedCell, pub app_vk: AssignedCell, pub app_data_static: AssignedCell, pub value: AssignedCell, @@ -544,14 +563,14 @@ pub struct NoteVariables { #[derive(Debug, Clone)] pub struct InputNoteVariables { pub nf: AssignedCell, - pub cm_x: AssignedCell, + pub cm: AssignedCell, pub note_variables: NoteVariables, } // Variables in the out note #[derive(Debug, Clone)] pub struct OutputNoteVariables { - pub cm_x: AssignedCell, + pub cm: AssignedCell, pub note_variables: NoteVariables, } @@ -581,32 +600,11 @@ impl BasicValidityPredicateVariables { let ret: Vec<_> = self .output_note_variables .iter() - .map(|variables| variables.cm_x.clone()) + .map(|variables| variables.cm.clone()) .collect(); ret.try_into().unwrap() } - pub fn get_address_searchable_pairs(&self) -> [NoteSearchableVariablePair; NUM_NOTE * 2] { - let mut input_note_pairs: Vec<_> = self - .input_note_variables - .iter() - .map(|variables| NoteSearchableVariablePair { - src_variable: variables.nf.clone(), - target_variable: variables.note_variables.address.clone(), - }) - .collect(); - let output_note_pairs: Vec<_> = self - .output_note_variables - .iter() - .map(|variables| NoteSearchableVariablePair { - src_variable: variables.cm_x.clone(), - target_variable: variables.note_variables.address.clone(), - }) - .collect(); - input_note_pairs.extend(output_note_pairs); - input_note_pairs.try_into().unwrap() - } - pub fn get_app_vk_searchable_pairs(&self) -> [NoteSearchableVariablePair; NUM_NOTE * 2] { let mut input_note_pairs: Vec<_> = self .input_note_variables @@ -620,7 +618,7 @@ impl BasicValidityPredicateVariables { .output_note_variables .iter() .map(|variables| NoteSearchableVariablePair { - src_variable: variables.cm_x.clone(), + src_variable: variables.cm.clone(), target_variable: variables.note_variables.app_vk.clone(), }) .collect(); @@ -643,7 +641,7 @@ impl BasicValidityPredicateVariables { .output_note_variables .iter() .map(|variables| NoteSearchableVariablePair { - src_variable: variables.cm_x.clone(), + src_variable: variables.cm.clone(), target_variable: variables.note_variables.app_data_static.clone(), }) .collect(); @@ -664,7 +662,7 @@ impl BasicValidityPredicateVariables { .output_note_variables .iter() .map(|variables| NoteSearchableVariablePair { - src_variable: variables.cm_x.clone(), + src_variable: variables.cm.clone(), target_variable: variables.note_variables.value.clone(), }) .collect(); @@ -687,7 +685,7 @@ impl BasicValidityPredicateVariables { .output_note_variables .iter() .map(|variables| NoteSearchableVariablePair { - src_variable: variables.cm_x.clone(), + src_variable: variables.cm.clone(), target_variable: variables.note_variables.is_merkle_checked.clone(), }) .collect(); @@ -710,7 +708,7 @@ impl BasicValidityPredicateVariables { .output_note_variables .iter() .map(|variables| NoteSearchableVariablePair { - src_variable: variables.cm_x.clone(), + src_variable: variables.cm.clone(), target_variable: variables.note_variables.app_data_dynamic.clone(), }) .collect(); @@ -732,7 +730,7 @@ impl BasicValidityPredicateVariables { .output_note_variables .iter() .map(|variables| NoteSearchableVariablePair { - src_variable: variables.cm_x.clone(), + src_variable: variables.cm.clone(), target_variable: variables.note_variables.rho.clone(), }) .collect(); @@ -754,7 +752,7 @@ impl BasicValidityPredicateVariables { .output_note_variables .iter() .map(|variables| NoteSearchableVariablePair { - src_variable: variables.cm_x.clone(), + src_variable: variables.cm.clone(), target_variable: variables.note_variables.nk_com.clone(), }) .collect(); @@ -776,7 +774,7 @@ impl BasicValidityPredicateVariables { .output_note_variables .iter() .map(|variables| NoteSearchableVariablePair { - src_variable: variables.cm_x.clone(), + src_variable: variables.cm.clone(), target_variable: variables.note_variables.psi.clone(), }) .collect(); @@ -798,7 +796,7 @@ impl BasicValidityPredicateVariables { .output_note_variables .iter() .map(|variables| NoteSearchableVariablePair { - src_variable: variables.cm_x.clone(), + src_variable: variables.cm.clone(), target_variable: variables.note_variables.rcm.clone(), }) .collect(); diff --git a/taiga_halo2/src/circuit/vp_examples/cascade_intent.rs b/taiga_halo2/src/circuit/vp_examples/cascade_intent.rs index 03500720..27eaece1 100644 --- a/taiga_halo2/src/circuit/vp_examples/cascade_intent.rs +++ b/taiga_halo2/src/circuit/vp_examples/cascade_intent.rs @@ -100,7 +100,7 @@ impl ValidityPredicateCircuit for CascadeIntentValidityPredicateCircuit { config.conditional_equal_config.assign_region( &is_input_note, &app_data_static, - &basic_variables.input_note_variables[1].cm_x, + &basic_variables.input_note_variables[1].cm, 0, &mut region, ) @@ -178,7 +178,7 @@ fn test_halo2_cascade_intent_vp_circuit() { let mut rng = OsRng; let circuit = { let cascade_input_note = random_input_note(&mut rng); - let cascade_note_cm = cascade_input_note.commitment().get_x(); + let cascade_note_cm = cascade_input_note.commitment().inner(); let rho = Nullifier::new(pallas::Base::random(&mut rng)); let nk = NullifierKeyContainer::random_key(&mut rng); let intent_note = create_intent_note(&mut rng, cascade_note_cm, rho, nk); diff --git a/taiga_halo2/src/circuit/vp_examples/or_relation_intent.rs b/taiga_halo2/src/circuit/vp_examples/or_relation_intent.rs index 2aab9fb0..f4168231 100644 --- a/taiga_halo2/src/circuit/vp_examples/or_relation_intent.rs +++ b/taiga_halo2/src/circuit/vp_examples/or_relation_intent.rs @@ -6,7 +6,7 @@ use crate::{ circuit::{ blake2s::publicize_default_dynamic_vp_commitments, gadgets::{ - assign_free_advice, assign_free_constant, + assign_free_advice, poseidon_hash::poseidon_hash_gadget, target_note_variable::{get_is_input_note_flag, get_owned_note_variable}, }, @@ -55,28 +55,29 @@ pub struct OrRelationIntentValidityPredicateCircuit { pub output_notes: [Note; NUM_NOTE], pub condition1: Condition, pub condition2: Condition, - pub receiver_address: pallas::Base, + pub receiver_nk_com: pallas::Base, + pub receiver_app_data_dynamic: pallas::Base, } impl OrRelationIntentValidityPredicateCircuit { pub fn encode_app_data_static( condition1: &Condition, condition2: &Condition, - receiver_address: pallas::Base, + receiver_nk_com: pallas::Base, + receiver_app_data_dynamic: pallas::Base, ) -> pallas::Base { let token_property_1 = transfrom_token_name_to_token_property(&condition1.token_name); let token_value_1 = pallas::Base::from(condition1.token_value); let token_property_2 = transfrom_token_name_to_token_property(&condition2.token_name); let token_value_2 = pallas::Base::from(condition2.token_value); - poseidon_hash_n::<8>([ + poseidon_hash_n([ token_property_1, token_value_1, token_property_2, token_value_2, TOKEN_VK.get_compressed(), - receiver_address, - pallas::Base::zero(), - pallas::Base::zero(), + receiver_nk_com, + receiver_app_data_dynamic, ]) } } @@ -132,21 +133,21 @@ impl ValidityPredicateCircuit for OrRelationIntentValidityPredicateCircuit { Value::known(pallas::Base::from(self.condition2.token_value)), )?; - let receiver_address = assign_free_advice( - layouter.namespace(|| "witness receiver address"), + let receiver_nk_com = assign_free_advice( + layouter.namespace(|| "witness receiver nk_com"), config.advices[0], - Value::known(self.receiver_address), + Value::known(self.receiver_nk_com), )?; - let padding_zero = assign_free_constant( - layouter.namespace(|| "zero"), + let receiver_app_data_dynamic = assign_free_advice( + layouter.namespace(|| "witness receiver app_data_dynamic"), config.advices[0], - pallas::Base::zero(), + Value::known(self.receiver_app_data_dynamic), )?; // Encode the app_data_static of intent note let encoded_app_data_static = poseidon_hash_gadget( - config.note_conifg.poseidon_config, + config.poseidon_config, layouter.namespace(|| "encode app_data_static"), [ token_property_1.clone(), @@ -154,9 +155,8 @@ impl ValidityPredicateCircuit for OrRelationIntentValidityPredicateCircuit { token_property_2.clone(), token_value_2.clone(), token_vp_vk.clone(), - receiver_address.clone(), - padding_zero.clone(), - padding_zero, + receiver_nk_com.clone(), + receiver_app_data_dynamic.clone(), ], )?; @@ -192,16 +192,32 @@ impl ValidityPredicateCircuit for OrRelationIntentValidityPredicateCircuit { }, )?; - // check the address of output note + // check nk_com layouter.assign_region( - || "conditional equal: check address", + || "conditional equal: check nk_com", |mut region| { config.conditional_equal_config.assign_region( &is_input_note, - &receiver_address, + &receiver_nk_com, &basic_variables.output_note_variables[0] .note_variables - .address, + .nk_com, + 0, + &mut region, + ) + }, + )?; + + // check app_data_dynamic + layouter.assign_region( + || "conditional equal: check app_data_dynamic", + |mut region| { + config.conditional_equal_config.assign_region( + &is_input_note, + &receiver_app_data_dynamic, + &basic_variables.output_note_variables[0] + .note_variables + .app_data_dynamic, 0, &mut region, ) @@ -272,14 +288,16 @@ pub fn create_intent_note( mut rng: R, condition1: &Condition, condition2: &Condition, - receiver_address: pallas::Base, + receiver_nk_com: pallas::Base, + receiver_app_data_dynamic: pallas::Base, rho: Nullifier, nk: NullifierKeyContainer, ) -> Note { let app_data_static = OrRelationIntentValidityPredicateCircuit::encode_app_data_static( condition1, condition2, - receiver_address, + receiver_nk_com, + receiver_app_data_dynamic, ); let rseed = RandomSeed::random(&mut rng); Note::new( @@ -323,15 +341,16 @@ fn test_halo2_or_relation_intent_vp_circuit() { output_notes[0].note_type.app_data_static = transfrom_token_name_to_token_property(&condition1.token_name); output_notes[0].value = condition1.token_value; - let receiver_address = output_notes[0].get_address(); let rho = Nullifier::new(pallas::Base::random(&mut rng)); let nk = NullifierKeyContainer::random_key(&mut rng); + let nk_com = output_notes[0].get_nk_commitment(); let intent_note = create_intent_note( &mut rng, &condition1, &condition2, - receiver_address, + nk_com, + output_notes[0].app_data_dynamic, rho, nk, ); @@ -343,7 +362,8 @@ fn test_halo2_or_relation_intent_vp_circuit() { output_notes, condition1, condition2, - receiver_address, + receiver_nk_com: nk_com, + receiver_app_data_dynamic: output_notes[0].app_data_dynamic, } }; let public_inputs = circuit.get_public_inputs(&mut rng); diff --git a/taiga_halo2/src/circuit/vp_examples/partial_fulfillment_intent.rs b/taiga_halo2/src/circuit/vp_examples/partial_fulfillment_intent.rs index 435adf90..df485021 100644 --- a/taiga_halo2/src/circuit/vp_examples/partial_fulfillment_intent.rs +++ b/taiga_halo2/src/circuit/vp_examples/partial_fulfillment_intent.rs @@ -49,30 +49,30 @@ pub struct PartialFulfillmentIntentValidityPredicateCircuit { pub output_notes: [Note; NUM_NOTE], pub sell: Token, pub buy: Token, - // address = Com(app_data_dynamic, nk_com). From `Note::get_address` - pub receiver_address: pallas::Base, + pub receiver_nk_com: pallas::Base, + pub receiver_app_data_dynamic: pallas::Base, } impl PartialFulfillmentIntentValidityPredicateCircuit { pub fn encode_app_data_static( sell: &Token, buy: &Token, - receiver_address: pallas::Base, + receiver_nk_com: pallas::Base, + receiver_app_data_dynamic: pallas::Base, ) -> pallas::Base { let sold_token = transfrom_token_name_to_token_property(&sell.name); let sold_token_value = pallas::Base::from(sell.value); let bought_token = transfrom_token_name_to_token_property(&buy.name); let bought_token_value = pallas::Base::from(buy.value); - poseidon_hash_n::<8>([ + poseidon_hash_n([ sold_token, sold_token_value, bought_token, bought_token_value, // Assuming the sold_token and bought_token have the same TOKEN_VK TOKEN_VK.get_compressed(), - receiver_address, - pallas::Base::zero(), - pallas::Base::zero(), + receiver_nk_com, + receiver_app_data_dynamic, ]) } } @@ -124,21 +124,21 @@ impl ValidityPredicateCircuit for PartialFulfillmentIntentValidityPredicateCircu Value::known(pallas::Base::from(self.buy.value)), )?; - let receiver_address = assign_free_advice( - layouter.namespace(|| "witness receiver address"), + let receiver_nk_com = assign_free_advice( + layouter.namespace(|| "witness receiver nk_com"), config.advices[0], - Value::known(self.receiver_address), + Value::known(self.receiver_nk_com), )?; - let padding_zero = assign_free_constant( - layouter.namespace(|| "zero"), + let receiver_app_data_dynamic = assign_free_advice( + layouter.namespace(|| "witness receiver app_data_dynamic"), config.advices[0], - pallas::Base::zero(), + Value::known(self.receiver_app_data_dynamic), )?; // Encode the app_data_static of intent note let encoded_app_data_static = poseidon_hash_gadget( - config.note_conifg.poseidon_config, + config.poseidon_config, layouter.namespace(|| "app_data_static encoding"), [ sold_token.clone(), @@ -146,9 +146,8 @@ impl ValidityPredicateCircuit for PartialFulfillmentIntentValidityPredicateCircu bought_token.clone(), bought_token_value.clone(), token_vp_vk.clone(), - receiver_address.clone(), - padding_zero.clone(), - padding_zero, + receiver_nk_com.clone(), + receiver_app_data_dynamic.clone(), ], )?; @@ -259,15 +258,32 @@ impl ValidityPredicateCircuit for PartialFulfillmentIntentValidityPredicateCircu }, )?; + // check nk_com layouter.assign_region( - || "conditional equal: check bought token address", + || "conditional equal: check bought token nk_com", |mut region| { config.conditional_equal_config.assign_region( &is_input_note, - &receiver_address, + &receiver_nk_com, &basic_variables.output_note_variables[0] .note_variables - .address, + .nk_com, + 0, + &mut region, + ) + }, + )?; + + // check app_data_dynamic + layouter.assign_region( + || "conditional equal: check bought token app_data_dynamic", + |mut region| { + config.conditional_equal_config.assign_region( + &is_input_note, + &receiver_app_data_dynamic, + &basic_variables.output_note_variables[0] + .note_variables + .app_data_dynamic, 0, &mut region, ) @@ -325,14 +341,29 @@ impl ValidityPredicateCircuit for PartialFulfillmentIntentValidityPredicateCircu )?; layouter.assign_region( - || "conditional equal: check returned token address", + || "conditional equal: check returned token nk_com", |mut region| { config.conditional_equal_config.assign_region( &is_partial_fulfillment, - &receiver_address, + &receiver_nk_com, &basic_variables.output_note_variables[1] .note_variables - .address, + .nk_com, + 0, + &mut region, + ) + }, + )?; + + layouter.assign_region( + || "conditional equal: check returned token app_data_dynamic", + |mut region| { + config.conditional_equal_config.assign_region( + &is_partial_fulfillment, + &receiver_app_data_dynamic, + &basic_variables.output_note_variables[1] + .note_variables + .app_data_dynamic, 0, &mut region, ) @@ -425,14 +456,16 @@ pub fn create_intent_note( mut rng: R, sell: &Token, buy: &Token, - receiver_address: pallas::Base, + receiver_nk_com: pallas::Base, + receiver_app_data_dynamic: pallas::Base, rho: Nullifier, nk: NullifierKeyContainer, ) -> Note { let app_data_static = PartialFulfillmentIntentValidityPredicateCircuit::encode_app_data_static( sell, buy, - receiver_address, + receiver_nk_com, + receiver_app_data_dynamic, ); let rseed = RandomSeed::random(&mut rng); Note::new( @@ -470,10 +503,18 @@ fn test_halo2_partial_fulfillment_intent_vp_circuit() { sold_note.note_type.app_vk = *COMPRESSED_TOKEN_VK; sold_note.note_type.app_data_static = transfrom_token_name_to_token_property(&sell.name); sold_note.value = sell.value; - let receiver_address = sold_note.get_address(); + let receiver_nk_com = sold_note.get_nk_commitment(); let rho = Nullifier::new(pallas::Base::random(&mut rng)); let nk = NullifierKeyContainer::random_key(&mut rng); - let intent_note = create_intent_note(&mut rng, &sell, &buy, receiver_address, rho, nk); + let intent_note = create_intent_note( + &mut rng, + &sell, + &buy, + receiver_nk_com, + sold_note.app_data_dynamic, + rho, + nk, + ); // Creating intent test { let input_padding_note = Note::random_padding_input_note(&mut rng); @@ -483,12 +524,13 @@ fn test_halo2_partial_fulfillment_intent_vp_circuit() { let output_notes = [intent_note, output_padding_note]; let circuit = PartialFulfillmentIntentValidityPredicateCircuit { - owned_note_pub_id: intent_note.commitment().get_x(), + owned_note_pub_id: intent_note.commitment().inner(), input_notes, output_notes, sell: sell.clone(), buy: buy.clone(), - receiver_address, + receiver_nk_com, + receiver_app_data_dynamic: sold_note.app_data_dynamic, }; let public_inputs = circuit.get_public_inputs(&mut rng); @@ -527,7 +569,8 @@ fn test_halo2_partial_fulfillment_intent_vp_circuit() { output_notes, sell: sell.clone(), buy: buy.clone(), - receiver_address, + receiver_nk_com, + receiver_app_data_dynamic: sold_note.app_data_dynamic, }; let public_inputs = circuit.get_public_inputs(&mut rng); @@ -555,7 +598,8 @@ fn test_halo2_partial_fulfillment_intent_vp_circuit() { output_notes, sell, buy, - receiver_address, + receiver_nk_com, + receiver_app_data_dynamic: sold_note.app_data_dynamic, }; let public_inputs = circuit.get_public_inputs(&mut rng); diff --git a/taiga_halo2/src/circuit/vp_examples/receiver_vp.rs b/taiga_halo2/src/circuit/vp_examples/receiver_vp.rs index 09617c99..3030e008 100644 --- a/taiga_halo2/src/circuit/vp_examples/receiver_vp.rs +++ b/taiga_halo2/src/circuit/vp_examples/receiver_vp.rs @@ -89,7 +89,7 @@ impl ValidityPredicateCircuit for ReceiverValidityPredicateCircuit { )?; // Construct an ECC chip - let ecc_chip = EccChip::construct(config.note_conifg.ecc_config); + let ecc_chip = EccChip::construct(config.ecc_config); let rcv_pk = NonIdentityPoint::new( ecc_chip.clone(), @@ -118,7 +118,7 @@ impl ValidityPredicateCircuit for ReceiverValidityPredicateCircuit { // Decode the app_data_dynamic, and check the app_data_dynamic encoding let encoded_app_data_dynamic = poseidon_hash_gadget( - config.note_conifg.poseidon_config.clone(), + config.poseidon_config.clone(), layouter.namespace(|| "app_data_dynamic encoding"), [ rcv_pk.inner().x(), @@ -205,7 +205,7 @@ impl ValidityPredicateCircuit for ReceiverValidityPredicateCircuit { layouter.namespace(|| "note encryption"), config.advices[0], config.instances, - config.note_conifg.poseidon_config, + config.poseidon_config, add_chip, ecc_chip, nonce, @@ -246,7 +246,7 @@ impl ValidityPredicateCircuit for ReceiverValidityPredicateCircuit { public_inputs.extend(custom_public_input_padding.iter()); assert_eq!(NUM_NOTE, 2); let target_note = - if self.get_owned_note_pub_id() == self.get_output_notes()[0].commitment().get_x() { + if self.get_owned_note_pub_id() == self.get_output_notes()[0].commitment().inner() { self.get_output_notes()[0] } else { self.get_output_notes()[1] @@ -311,7 +311,7 @@ fn test_halo2_receiver_vp_circuit() { *COMPRESSED_TOKEN_AUTH_VK, *COMPRESSED_RECEIVER_VK, ]); - let owned_note_pub_id = output_notes[0].commitment().get_x(); + let owned_note_pub_id = output_notes[0].commitment().inner(); ( ReceiverValidityPredicateCircuit { owned_note_pub_id, diff --git a/taiga_halo2/src/circuit/vp_examples/signature_verification.rs b/taiga_halo2/src/circuit/vp_examples/signature_verification.rs index 1a0f3fc3..a1c17f96 100644 --- a/taiga_halo2/src/circuit/vp_examples/signature_verification.rs +++ b/taiga_halo2/src/circuit/vp_examples/signature_verification.rs @@ -136,7 +136,7 @@ impl SignatureVerificationValidityPredicateCircuit { let nf = input_note.get_nf().unwrap().inner(); message.push(nf); let cm = output_note.commitment(); - message.push(cm.get_x()); + message.push(cm.inner()); }); let signature = SchnorrSignature::sign(&mut rng, sk, message); Self { @@ -159,7 +159,7 @@ impl ValidityPredicateCircuit for SignatureVerificationValidityPredicateCircuit basic_variables: BasicValidityPredicateVariables, ) -> Result<(), Error> { // Construct an ECC chip - let ecc_chip = EccChip::construct(config.note_conifg.ecc_config); + let ecc_chip = EccChip::construct(config.ecc_config); let pk = NonIdentityPoint::new( ecc_chip.clone(), @@ -189,7 +189,7 @@ impl ValidityPredicateCircuit for SignatureVerificationValidityPredicateCircuit // Decode the app_data_dynamic, and check the app_data_dynamic encoding let encoded_app_data_dynamic = poseidon_hash_gadget( - config.note_conifg.poseidon_config.clone(), + config.poseidon_config.clone(), layouter.namespace(|| "app_data_dynamic encoding"), [pk.inner().x(), pk.inner().y(), auth_vp_vk, receiver_vp_vk], )?; @@ -224,7 +224,7 @@ impl ValidityPredicateCircuit for SignatureVerificationValidityPredicateCircuit let cms = basic_variables.get_output_note_cms(); assert_eq!(NUM_NOTE, 2); let h = poseidon_hash_gadget( - config.note_conifg.poseidon_config, + config.poseidon_config, layouter.namespace(|| "Poseidon_hash(r, P, m)"), [ r.inner().x(), diff --git a/taiga_halo2/src/circuit/vp_examples/token.rs b/taiga_halo2/src/circuit/vp_examples/token.rs index 95be8221..43a72352 100644 --- a/taiga_halo2/src/circuit/vp_examples/token.rs +++ b/taiga_halo2/src/circuit/vp_examples/token.rs @@ -135,7 +135,7 @@ impl ValidityPredicateCircuit for TokenValidityPredicateCircuit { )?; // Construct an ECC chip - let ecc_chip = EccChip::construct(config.note_conifg.ecc_config); + let ecc_chip = EccChip::construct(config.ecc_config); let pk = NonIdentityPoint::new( ecc_chip, @@ -165,7 +165,7 @@ impl ValidityPredicateCircuit for TokenValidityPredicateCircuit { // Decode the app_data_dynamic, and check the app_data_dynamic encoding let encoded_app_data_dynamic = poseidon_hash_gadget( - config.note_conifg.poseidon_config, + config.poseidon_config, layouter.namespace(|| "app_data_dynamic encoding"), [ pk.inner().x(), @@ -283,8 +283,8 @@ impl ValidityPredicateCircuit for TokenValidityPredicateCircuit { fn get_public_inputs(&self, mut rng: impl RngCore) -> ValidityPredicatePublicInputs { let mut public_inputs = self.get_mandatory_public_inputs(); - let dynamic_vp = if self.owned_note_pub_id == self.output_notes[0].commitment().get_x() - || self.owned_note_pub_id == self.output_notes[1].commitment().get_x() + let dynamic_vp = if self.owned_note_pub_id == self.output_notes[0].commitment().inner() + || self.owned_note_pub_id == self.output_notes[1].commitment().inner() { self.receiver_vp_vk } else { @@ -394,7 +394,7 @@ pub fn generate_output_token_note_proving_info( input_notes: [Note; NUM_NOTE], output_notes: [Note; NUM_NOTE], ) -> OutputNoteProvingInfo { - let owned_note_pub_id = output_note.commitment().get_x(); + let owned_note_pub_id = output_note.commitment().inner(); // token VP let token_vp = TokenValidityPredicateCircuit { owned_note_pub_id, diff --git a/taiga_halo2/src/merkle_tree.rs b/taiga_halo2/src/merkle_tree.rs index 0c501d23..ab1ea786 100644 --- a/taiga_halo2/src/merkle_tree.rs +++ b/taiga_halo2/src/merkle_tree.rs @@ -110,11 +110,11 @@ impl Node { } pub fn from_note(n: &Note) -> Self { - Self(n.commitment().get_x()) + Self(n.commitment().inner()) } pub fn from_note_commitment(n: &NoteCommitment) -> Self { - Self(n.get_x()) + Self(n.inner()) } pub fn rand(rng: &mut impl RngCore) -> Self { diff --git a/taiga_halo2/src/note.rs b/taiga_halo2/src/note.rs index 489a7990..ecb2337a 100644 --- a/taiga_halo2/src/note.rs +++ b/taiga_halo2/src/note.rs @@ -4,25 +4,20 @@ use crate::{ vp_examples::{TrivialValidityPredicateCircuit, COMPRESSED_TRIVIAL_VP_VK}, }, constant::{ - BASE_BITS_NUM, NOTE_COMMIT_DOMAIN, NUM_NOTE, POSEIDON_TO_CURVE_INPUT_LEN, - PRF_EXPAND_PERSONALIZATION, PRF_EXPAND_PSI, PRF_EXPAND_PUBLIC_INPUT_PADDING, - PRF_EXPAND_RCM, PRF_EXPAND_VCM_R, + NUM_NOTE, POSEIDON_TO_CURVE_INPUT_LEN, PRF_EXPAND_PERSONALIZATION, PRF_EXPAND_PSI, + PRF_EXPAND_PUBLIC_INPUT_PADDING, PRF_EXPAND_RCM, PRF_EXPAND_VCM_R, }, merkle_tree::MerklePath, nullifier::{Nullifier, NullifierKeyContainer}, - utils::{extract_p, mod_r_p, poseidon_hash, poseidon_to_curve}, + utils::{poseidon_hash_n, poseidon_to_curve}, }; -use bitvec::{array::BitArray, order::Lsb0}; use blake2b_simd::Params as Blake2bParams; -use core::iter; use ff::{FromUniformBytes, PrimeField}; use halo2_proofs::arithmetic::Field; -use pasta_curves::{ - group::{ff::PrimeFieldBits, Group, GroupEncoding}, - pallas, -}; +use pasta_curves::pallas; use rand::RngCore; use std::hash::{Hash, Hasher}; +use subtle::CtOption; #[cfg(feature = "nif")] use rustler::{NifStruct, NifTuple}; @@ -34,35 +29,29 @@ use serde; use borsh::{BorshDeserialize, BorshSerialize}; /// A commitment to a note. -#[derive(Copy, Debug, Clone, PartialEq, Eq)] +#[derive(Copy, Debug, Clone, PartialEq, Eq, Default)] #[cfg_attr(feature = "nif", derive(NifTuple))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct NoteCommitment(pallas::Point); +pub struct NoteCommitment(pallas::Base); impl NoteCommitment { - pub fn inner(&self) -> pallas::Point { + pub fn inner(&self) -> pallas::Base { self.0 } - pub fn get_x(&self) -> pallas::Base { - extract_p(&self.0) - } - pub fn to_bytes(&self) -> [u8; 32] { - self.0.to_bytes() + self.0.to_repr() } -} -impl Default for NoteCommitment { - fn default() -> NoteCommitment { - NoteCommitment(pallas::Point::generator()) + pub fn from_bytes(bytes: [u8; 32]) -> CtOption { + pallas::Base::from_repr(bytes).map(NoteCommitment) } } #[cfg(feature = "borsh")] impl BorshSerialize for NoteCommitment { fn serialize(&self, writer: &mut W) -> std::io::Result<()> { - writer.write_all(&self.0.to_bytes())?; + writer.write_all(&self.to_bytes())?; Ok(()) } } @@ -72,8 +61,11 @@ impl BorshDeserialize for NoteCommitment { fn deserialize_reader(reader: &mut R) -> std::io::Result { let mut repr = [0u8; 32]; reader.read_exact(&mut repr)?; - let value = Option::from(pallas::Point::from_bytes(&repr)).ok_or_else(|| { - std::io::Error::new(std::io::ErrorKind::InvalidData, "Node value not in field") + let value = Option::from(pallas::Base::from_repr(repr)).ok_or_else(|| { + std::io::Error::new( + std::io::ErrorKind::InvalidData, + "NoteCommitment value not in field", + ) })?; Ok(Self(value)) } @@ -81,7 +73,7 @@ impl BorshDeserialize for NoteCommitment { impl Hash for NoteCommitment { fn hash(&self, state: &mut H) { - self.0.to_bytes().as_ref().hash(state); + self.to_bytes().as_ref().hash(state); } } @@ -227,51 +219,20 @@ impl Note { is_merkle_checked: false, } } - // cm = SinsemillaCommit^rcm(address || app_vk || app_data_static || rho || psi || is_merkle_checked || value) + + // note_commitment = poseidon_hash(app_vk || app_data_static || app_data_dynamic || nk_commitment || rho || psi || is_merkle_checked || value || rcm) pub fn commitment(&self) -> NoteCommitment { - let address = self.get_address(); - let ret = NOTE_COMMIT_DOMAIN - .commit( - iter::empty() - .chain(address.to_le_bits().iter().by_vals().take(BASE_BITS_NUM)) - .chain( - self.get_app_vk() - .to_le_bits() - .iter() - .by_vals() - .take(BASE_BITS_NUM), - ) - .chain( - self.get_app_data_static() - .to_le_bits() - .iter() - .by_vals() - .take(BASE_BITS_NUM), - ) - .chain( - self.rho - .inner() - .to_le_bits() - .iter() - .by_vals() - .take(BASE_BITS_NUM), - ) - .chain( - self.get_psi() - .to_le_bits() - .iter() - .by_vals() - .take(BASE_BITS_NUM), - ) - .chain([self.is_merkle_checked]) - .chain( - BitArray::<_, Lsb0>::new(self.value.to_le()) - .iter() - .by_vals(), - ), - &mod_r_p(self.get_rcm()), - ) - .unwrap(); + let ret = poseidon_hash_n([ + self.get_app_vk(), + self.get_app_data_static(), + self.app_data_dynamic, + self.get_nk_commitment(), + self.rho.inner(), + self.psi, + pallas::Base::from(self.is_merkle_checked as u64), + pallas::Base::from(self.value), + self.rcm, + ]); NoteCommitment(ret) } @@ -284,10 +245,6 @@ impl Note { ) } - pub fn get_address(&self) -> pallas::Base { - poseidon_hash(self.app_data_dynamic, self.get_nk_commitment()) - } - pub fn get_nk(&self) -> Option { self.nk_container.get_nk() } @@ -586,7 +543,7 @@ impl OutputNoteProvingInfo { output_notes: [Note; NUM_NOTE], ) -> Self { let trivail_vp = Box::new(TrivialValidityPredicateCircuit { - owned_note_pub_id: padding_note.commitment().get_x(), + owned_note_pub_id: padding_note.commitment().inner(), input_notes, output_notes, }); diff --git a/taiga_halo2/src/nullifier.rs b/taiga_halo2/src/nullifier.rs index 6c512b0d..4ff50f2b 100644 --- a/taiga_halo2/src/nullifier.rs +++ b/taiga_halo2/src/nullifier.rs @@ -1,12 +1,10 @@ use std::hash::Hash; -use crate::constant::GENERATOR; use crate::{ note::NoteCommitment, - utils::{extract_p, mod_r_p, prf_nf}, + utils::{poseidon_hash_n, prf_nf}, }; use halo2_proofs::arithmetic::Field; -use pasta_curves::group::cofactor::CofactorCurveAffine; use pasta_curves::group::ff::PrimeField; use pasta_curves::pallas; use rand::RngCore; @@ -42,8 +40,8 @@ impl Nullifier { Self(nf) } - // cm is a point - // $nf =Extract_P([PRF_{nk}(\rho) + \psi \ mod \ q] * K + cm)$ + // cm is a field element + // nf = poseidon_hash(nk || \rho || \psi || note_cm) pub fn derive( nk: &NullifierKeyContainer, rho: &pallas::Base, @@ -53,11 +51,7 @@ impl Nullifier { match nk { NullifierKeyContainer::Commitment(_) => None, NullifierKeyContainer::Key(key) => { - let k = GENERATOR.to_curve(); - - let nf = Nullifier(extract_p( - &(k * mod_r_p(prf_nf(*key, *rho) + psi) + cm.inner()), - )); + let nf = Nullifier(poseidon_hash_n([*key, *rho, *psi, cm.inner()])); Some(nf) } } diff --git a/taiga_halo2/src/shielded_ptx.rs b/taiga_halo2/src/shielded_ptx.rs index 4b8e5b17..c33e43ec 100644 --- a/taiga_halo2/src/shielded_ptx.rs +++ b/taiga_halo2/src/shielded_ptx.rs @@ -232,7 +232,7 @@ impl Executable for ShieldedPartialTransaction { fn get_output_cms(&self) -> Vec { self.actions .iter() - .map(|action| action.action_instance.cm_x) + .map(|action| action.action_instance.cm) .collect() } @@ -536,12 +536,12 @@ pub mod testing { dynamic_vps.clone(), ); - trivial_vp_circuit.owned_note_pub_id = output_note_1.commitment().get_x(); + trivial_vp_circuit.owned_note_pub_id = output_note_1.commitment().inner(); let output_application_vp_1 = Box::new(trivial_vp_circuit.clone()); let output_note_proving_info_1 = OutputNoteProvingInfo::new(output_note_1, output_application_vp_1, dynamic_vps.clone()); - trivial_vp_circuit.owned_note_pub_id = output_note_2.commitment().get_x(); + trivial_vp_circuit.owned_note_pub_id = output_note_2.commitment().inner(); let output_application_vp_2 = Box::new(trivial_vp_circuit); let output_note_proving_info_2 = OutputNoteProvingInfo::new(output_note_2, output_application_vp_2, dynamic_vps); diff --git a/taiga_halo2/src/vp_commitment.rs b/taiga_halo2/src/vp_commitment.rs index d96e66eb..86e8a0d0 100644 --- a/taiga_halo2/src/vp_commitment.rs +++ b/taiga_halo2/src/vp_commitment.rs @@ -2,6 +2,8 @@ use crate::constant::VP_COMMITMENT_PERSONALIZATION; use blake2s_simd::Params; use byteorder::{ByteOrder, LittleEndian}; use ff::PrimeField; +#[cfg(feature = "nif")] +use rustler::{Decoder, Encoder, Env, NifResult, Term}; #[cfg(feature = "serde")] use serde; @@ -42,3 +44,21 @@ impl ValidityPredicateCommitment { [low, high] } } + +#[cfg(feature = "nif")] +impl Encoder for ValidityPredicateCommitment { + fn encode<'a>(&self, env: Env<'a>) -> Term<'a> { + self.0.to_vec().encode(env) + } +} + +#[cfg(feature = "nif")] +impl<'a> Decoder<'a> for ValidityPredicateCommitment { + fn decode(term: Term<'a>) -> NifResult { + let val: Vec = Decoder::decode(term)?; + let val_array = val + .try_into() + .map_err(|_e| rustler::Error::Atom("failure to decode"))?; + Ok(ValidityPredicateCommitment(val_array)) + } +}