From 4770ea17647fd1a85388c1299cd13a46c8adf92b Mon Sep 17 00:00:00 2001 From: Xuyang Song Date: Wed, 8 Nov 2023 05:37:47 -0600 Subject: [PATCH] refactor shielded ptx building (#235) * refactor shielded ptx building * generate the rseed of action inside of the new function and improve the anchor calculation * automatically reset the rho of output note when constructing the Action * simplify the random and padding note creation * fix typo * rename reset_rho to set_rho --- taiga_halo2/benches/action_proof.rs | 12 +- .../cascaded_partial_transactions.rs | 254 +++++++++-------- .../partial_fulfillment_token_swap.rs | 218 ++++++++------- taiga_halo2/examples/tx_examples/token.rs | 116 ++++---- .../tx_examples/token_swap_with_intent.rs | 259 ++++++++++-------- .../tx_examples/token_swap_without_intent.rs | 12 +- taiga_halo2/src/action.rs | 54 ++-- taiga_halo2/src/circuit/vp_examples.rs | 18 +- .../src/circuit/vp_examples/cascade_intent.rs | 24 +- .../src/circuit/vp_examples/field_addition.rs | 11 +- .../circuit/vp_examples/or_relation_intent.rs | 24 +- .../vp_examples/partial_fulfillment_intent.rs | 7 +- .../partial_fulfillment_intent/swap.rs | 27 +- .../src/circuit/vp_examples/receiver_vp.rs | 14 +- .../vp_examples/signature_verification.rs | 11 +- taiga_halo2/src/circuit/vp_examples/token.rs | 69 +++-- taiga_halo2/src/note.rs | 215 ++++++--------- taiga_halo2/src/shielded_ptx.rs | 145 +++++----- taiga_halo2/src/taiga_api.rs | 59 ++-- taiga_halo2/src/transparent_ptx.rs | 49 +++- 20 files changed, 796 insertions(+), 802 deletions(-) diff --git a/taiga_halo2/benches/action_proof.rs b/taiga_halo2/benches/action_proof.rs index 9cf5ef64..fa1dfc88 100644 --- a/taiga_halo2/benches/action_proof.rs +++ b/taiga_halo2/benches/action_proof.rs @@ -43,7 +43,7 @@ fn bench_action_proof(name: &str, c: &mut Criterion) { rho, } }; - let output_note = { + let mut output_note = { let rho = input_note.get_nf().unwrap(); let nk_com = NullifierKeyContainer::from_commitment(pallas::Base::random(&mut rng)); let note_type = { @@ -66,9 +66,13 @@ fn bench_action_proof(name: &str, c: &mut Criterion) { } }; let input_merkle_path = MerklePath::random(&mut rng, TAIGA_COMMITMENT_TREE_DEPTH); - let anchor = input_note.calculate_root(&input_merkle_path); - let rseed = RandomSeed::random(&mut rng); - ActionInfo::new(input_note, input_merkle_path, anchor, output_note, rseed) + ActionInfo::new( + input_note, + input_merkle_path, + None, + &mut output_note, + &mut rng, + ) }; let (action, action_circuit) = action_info.build(); let params = SETUP_PARAMS_MAP.get(&ACTION_CIRCUIT_PARAMS_SIZE).unwrap(); diff --git a/taiga_halo2/examples/tx_examples/cascaded_partial_transactions.rs b/taiga_halo2/examples/tx_examples/cascaded_partial_transactions.rs index 617ae0ce..d9b4b4d7 100644 --- a/taiga_halo2/examples/tx_examples/cascaded_partial_transactions.rs +++ b/taiga_halo2/examples/tx_examples/cascaded_partial_transactions.rs @@ -5,6 +5,7 @@ use halo2_proofs::arithmetic::Field; use pasta_curves::pallas; use rand::{CryptoRng, RngCore}; use taiga_halo2::{ + action::ActionInfo, circuit::vp_examples::{ cascade_intent::{create_intent_note, CascadeIntentValidityPredicateCircuit}, signature_verification::COMPRESSED_TOKEN_AUTH_VK, @@ -12,8 +13,7 @@ use taiga_halo2::{ }, constant::TAIGA_COMMITMENT_TREE_DEPTH, merkle_tree::{Anchor, MerklePath}, - note::{InputNoteProvingInfo, OutputNoteProvingInfo}, - nullifier::{Nullifier, NullifierKeyContainer}, + note::NoteValidityPredicates, shielded_ptx::ShieldedPartialTransaction, transaction::{ShieldedPartialTxBundle, Transaction, TransparentPartialTxBundle}, }; @@ -21,46 +21,29 @@ use taiga_halo2::{ pub fn create_transaction(mut rng: R) -> Transaction { let alice_auth_sk = pallas::Scalar::random(&mut rng); let alice_auth = TokenAuthorization::from_sk_vk(&alice_auth_sk, &COMPRESSED_TOKEN_AUTH_VK); - let alice_nk = NullifierKeyContainer::random_key(&mut rng); + let alice_nk = pallas::Base::random(&mut rng); let bob_auth = TokenAuthorization::random(&mut rng); - let bob_nk_com = NullifierKeyContainer::random_commitment(&mut rng); + let bob_nk_com = pallas::Base::random(&mut rng); - let rho = Nullifier::from(pallas::Base::random(&mut rng)); let input_token_1 = Token::new("btc".to_string(), 1u64); - let input_note_1 = input_token_1.create_random_token_note(&mut rng, rho, alice_nk, &alice_auth); + let input_note_1 = + input_token_1.create_random_input_token_note(&mut rng, alice_nk, &alice_auth); let output_token_1 = Token::new("btc".to_string(), 1u64); - let output_note_1 = output_token_1.create_random_token_note( - &mut rng, - input_note_1.get_nf().unwrap(), - bob_nk_com, - &bob_auth, - ); + let mut output_note_1 = output_token_1.create_random_output_token_note(bob_nk_com, &bob_auth); let input_token_2 = Token::new("eth".to_string(), 2u64); - let input_note_2 = input_token_2.create_random_token_note(&mut rng, rho, alice_nk, &alice_auth); + let input_note_2 = + input_token_2.create_random_input_token_note(&mut rng, alice_nk, &alice_auth); let input_token_3 = Token::new("xan".to_string(), 3u64); - let input_note_3 = input_token_3.create_random_token_note(&mut rng, rho, alice_nk, &alice_auth); - let cascade_intent_note = create_intent_note( - &mut rng, - input_note_3.commitment().inner(), - input_note_2.get_nf().unwrap(), - alice_nk, - ); + let input_note_3 = + input_token_3.create_random_input_token_note(&mut rng, alice_nk, &alice_auth); + let mut cascade_intent_note = + create_intent_note(&mut rng, input_note_3.commitment().inner(), alice_nk); let output_token_2 = Token::new("eth".to_string(), 2u64); - let output_note_2 = output_token_2.create_random_token_note( - &mut rng, - cascade_intent_note.get_nf().unwrap(), - bob_nk_com, - &bob_auth, - ); + let mut output_note_2 = output_token_2.create_random_output_token_note(bob_nk_com, &bob_auth); let output_token_3 = Token::new("xan".to_string(), 3u64); - let output_note_3 = output_token_3.create_random_token_note( - &mut rng, - input_note_3.get_nf().unwrap(), - bob_nk_com, - &bob_auth, - ); + let mut output_note_3 = output_token_3.create_random_output_token_note(bob_nk_com, &bob_auth); let merkle_path = MerklePath::random(&mut rng, TAIGA_COMMITMENT_TREE_DEPTH); @@ -71,106 +54,153 @@ pub fn create_transaction(mut rng: R) -> Transaction { // Alice consumes 1 "BTC" and 2 "ETH". // Alice creates a cascade intent note and 1 "BTC" to Bob. let ptx_1 = { - let input_notes = [*input_note_1.note(), *input_note_2.note()]; - let output_notes = [*output_note_1.note(), cascade_intent_note]; - // Create the input note proving info - let input_note_1_proving_info = input_note_1.generate_input_token_note_proving_info( - &mut rng, - alice_auth, - alice_auth_sk, - merkle_path.clone(), - input_notes, - output_notes, - ); - let input_note_2_proving_info = input_note_2.generate_input_token_note_proving_info( - &mut rng, - alice_auth, - alice_auth_sk, - merkle_path.clone(), - input_notes, - output_notes, - ); - - // Create the output note proving info - let output_note_1_proving_info = output_note_1.generate_output_token_note_proving_info( - &mut rng, - bob_auth, - input_notes, - output_notes, - ); - - let intent_note_proving_info = { - let intent_vp = CascadeIntentValidityPredicateCircuit { - owned_note_pub_id: cascade_intent_note.commitment().inner(), + // Create action pairs + let actions = { + let action_1 = ActionInfo::new( + *input_note_1.note(), + merkle_path.clone(), + None, + &mut output_note_1.note, + &mut rng, + ); + + let action_2 = ActionInfo::new( + *input_note_2.note(), + merkle_path.clone(), + None, + &mut cascade_intent_note, + &mut rng, + ); + vec![action_1, action_2] + }; + + // Create VPs + let (input_vps, output_vps) = { + let input_notes = [*input_note_1.note(), *input_note_2.note()]; + let output_notes = [*output_note_1.note(), cascade_intent_note]; + + // Create the input note_1 vps + let input_note_1_vps = input_note_1.generate_input_token_vps( + &mut rng, + alice_auth, + alice_auth_sk, input_notes, output_notes, - cascade_note_cm: cascade_intent_note.get_app_data_static(), + ); + + // Create the input note_2 vps + let input_note_2_vps = input_note_2.generate_input_token_vps( + &mut rng, + alice_auth, + alice_auth_sk, + input_notes, + output_notes, + ); + + // Create the output note_1 vps + let output_note_1_vps = output_note_1.generate_output_token_vps( + &mut rng, + bob_auth, + input_notes, + output_notes, + ); + + // Create intent vps + let intent_vps = { + let intent_vp = CascadeIntentValidityPredicateCircuit { + owned_note_pub_id: cascade_intent_note.commitment().inner(), + input_notes, + output_notes, + cascade_note_cm: cascade_intent_note.get_app_data_static(), + }; + + NoteValidityPredicates::new(Box::new(intent_vp), vec![]) }; - OutputNoteProvingInfo::new(cascade_intent_note, Box::new(intent_vp), vec![]) + ( + vec![input_note_1_vps, input_note_2_vps], + vec![output_note_1_vps, intent_vps], + ) }; // Create shielded partial tx - ShieldedPartialTransaction::build( - [input_note_1_proving_info, input_note_2_proving_info], - [output_note_1_proving_info, intent_note_proving_info], - vec![], - &mut rng, - ) + ShieldedPartialTransaction::build(actions, input_vps, output_vps, vec![], &mut rng).unwrap() }; // The second partial transaction: // Alice consumes the intent note and 3 "XAN"; // Alice creates 2 "ETH" and 3 "XAN" to Bob let ptx_2 = { - let input_notes = [cascade_intent_note, *input_note_3.note()]; - let output_notes = [*output_note_2.note(), *output_note_3.note()]; - // Create the input note proving info - let intent_note_proving_info = { - let intent_vp = CascadeIntentValidityPredicateCircuit { - owned_note_pub_id: cascade_intent_note.get_nf().unwrap().inner(), - input_notes, - output_notes, - cascade_note_cm: cascade_intent_note.get_app_data_static(), - }; - - InputNoteProvingInfo::new( + // Create action pairs + let actions = { + let action_1 = ActionInfo::new( cascade_intent_note, merkle_path.clone(), Some(anchor), - Box::new(intent_vp), - vec![], + &mut output_note_2.note, + &mut rng, + ); + + let action_2 = ActionInfo::new( + *input_note_3.note(), + merkle_path, + None, + &mut output_note_3.note, + &mut rng, + ); + vec![action_1, action_2] + }; + + // Create VPs + let (input_vps, output_vps) = { + let input_notes = [cascade_intent_note, *input_note_3.note()]; + let output_notes = [*output_note_2.note(), *output_note_3.note()]; + + // Create intent vps + let intent_vps = { + let intent_vp = CascadeIntentValidityPredicateCircuit { + owned_note_pub_id: cascade_intent_note.get_nf().unwrap().inner(), + input_notes, + output_notes, + cascade_note_cm: cascade_intent_note.get_app_data_static(), + }; + + NoteValidityPredicates::new(Box::new(intent_vp), vec![]) + }; + + // Create input note_3 vps + let input_note_3_vps = input_note_3.generate_input_token_vps( + &mut rng, + alice_auth, + alice_auth_sk, + input_notes, + output_notes, + ); + + // Create output note_2 vps + let output_note_2_vps = output_note_2.generate_output_token_vps( + &mut rng, + bob_auth, + input_notes, + output_notes, + ); + + // Create output note_3 vps + let output_note_3_vps = output_note_3.generate_output_token_vps( + &mut rng, + bob_auth, + input_notes, + output_notes, + ); + + ( + vec![intent_vps, input_note_3_vps], + vec![output_note_2_vps, output_note_3_vps], ) }; - let input_note_3_proving_info = input_note_3.generate_input_token_note_proving_info( - &mut rng, - alice_auth, - alice_auth_sk, - merkle_path, - input_notes, - output_notes, - ); - // Create the output note proving info - let output_note_2_proving_info = output_note_2.generate_output_token_note_proving_info( - &mut rng, - bob_auth, - input_notes, - output_notes, - ); - let output_note_3_proving_info = output_note_3.generate_output_token_note_proving_info( - &mut rng, - bob_auth, - input_notes, - output_notes, - ); // Create shielded partial tx - ShieldedPartialTransaction::build( - [intent_note_proving_info, input_note_3_proving_info], - [output_note_2_proving_info, output_note_3_proving_info], - vec![], - &mut rng, - ) + ShieldedPartialTransaction::build(actions, input_vps, output_vps, vec![], &mut rng).unwrap() }; // Create the final transaction 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 9f64b44b..95efd62f 100644 --- a/taiga_halo2/examples/tx_examples/partial_fulfillment_token_swap.rs +++ b/taiga_halo2/examples/tx_examples/partial_fulfillment_token_swap.rs @@ -9,6 +9,7 @@ use halo2_proofs::arithmetic::Field; use pasta_curves::{group::Curve, pallas}; use rand::{CryptoRng, RngCore}; use taiga_halo2::{ + action::ActionInfo, circuit::vp_examples::{ partial_fulfillment_intent::{PartialFulfillmentIntentValidityPredicateCircuit, Swap}, signature_verification::COMPRESSED_TOKEN_AUTH_VK, @@ -16,7 +17,7 @@ use taiga_halo2::{ }, constant::TAIGA_COMMITMENT_TREE_DEPTH, merkle_tree::{Anchor, MerklePath}, - note::{InputNoteProvingInfo, Note, OutputNoteProvingInfo}, + note::{Note, NoteValidityPredicates}, nullifier::NullifierKeyContainer, shielded_ptx::ShieldedPartialTransaction, transaction::{ShieldedPartialTxBundle, Transaction, TransparentPartialTxBundle}, @@ -30,66 +31,83 @@ pub fn create_token_intent_ptx( ) -> (ShieldedPartialTransaction, Swap, Note) { let input_auth = TokenAuthorization::from_sk_vk(&input_auth_sk, &COMPRESSED_TOKEN_AUTH_VK); let swap = Swap::random(&mut rng, sell, buy, input_auth); - let intent_note = swap.create_intent_note(&mut rng); + let mut intent_note = swap.create_intent_note(&mut rng); // padding the zero notes - let padding_input_note = Note::random_padding_input_note(&mut rng); - let padding_input_note_nf = padding_input_note.get_nf().unwrap(); - let padding_output_note = Note::random_padding_output_note(&mut rng, padding_input_note_nf); - - let input_notes = [*swap.sell.note(), padding_input_note]; - let output_notes = [intent_note, padding_output_note]; - + let padding_input_note = Note::random_padding_note(&mut rng); + let mut padding_output_note = Note::random_padding_note(&mut rng); let merkle_path = MerklePath::random(&mut rng, TAIGA_COMMITMENT_TREE_DEPTH); - // Fetch a valid anchor for dummy notes - let anchor = Anchor::from(pallas::Base::random(&mut rng)); - - // Create the input note proving info - let input_note_proving_info = swap.sell.generate_input_token_note_proving_info( - &mut rng, - input_auth, - input_auth_sk, - merkle_path.clone(), - input_notes, - output_notes, - ); + // Create action pairs + let actions = { + let action_1 = ActionInfo::new( + *swap.sell.note(), + merkle_path.clone(), + None, + &mut intent_note, + &mut rng, + ); + + // Fetch a valid anchor for dummy notes + let anchor = Anchor::from(pallas::Base::random(&mut rng)); + let action_2 = ActionInfo::new( + padding_input_note, + merkle_path, + Some(anchor), + &mut padding_output_note, + &mut rng, + ); + vec![action_1, action_2] + }; - // Create the intent note proving info - let intent_note_proving_info = { - let intent_vp = PartialFulfillmentIntentValidityPredicateCircuit { - owned_note_pub_id: intent_note.commitment().inner(), + // Create VPs + let (input_vps, output_vps) = { + let input_notes = [*swap.sell.note(), padding_input_note]; + let output_notes = [intent_note, padding_output_note]; + // Create the input token vps + let input_token_vps = swap.sell.generate_input_token_vps( + &mut rng, + input_auth, + input_auth_sk, input_notes, output_notes, - swap: swap.clone(), + ); + + // Create the intent vps + let intent_vps = { + let intent_vp = PartialFulfillmentIntentValidityPredicateCircuit { + owned_note_pub_id: intent_note.commitment().inner(), + input_notes, + output_notes, + swap: swap.clone(), + }; + + NoteValidityPredicates::new(Box::new(intent_vp), vec![]) }; - OutputNoteProvingInfo::new(intent_note, Box::new(intent_vp), vec![]) - }; + // Create the padding input vps + let padding_input_vps = NoteValidityPredicates::create_input_padding_note_vps( + &padding_input_note, + input_notes, + output_notes, + ); - // Create the padding input note proving info - let padding_input_note_proving_info = InputNoteProvingInfo::create_padding_note_proving_info( - padding_input_note, - merkle_path, - anchor, - input_notes, - output_notes, - ); + // Create the padding output vps + let padding_output_vps = NoteValidityPredicates::create_output_padding_note_vps( + &padding_output_note, + input_notes, + output_notes, + ); - // Create the padding output note proving info - let padding_output_note_proving_info = OutputNoteProvingInfo::create_padding_note_proving_info( - padding_output_note, - input_notes, - output_notes, - ); + ( + vec![input_token_vps, padding_input_vps], + vec![intent_vps, padding_output_vps], + ) + }; // Create shielded partial tx - let ptx = ShieldedPartialTransaction::build( - [input_note_proving_info, padding_input_note_proving_info], - [intent_note_proving_info, padding_output_note_proving_info], - vec![], - &mut rng, - ); + let ptx = ShieldedPartialTransaction::build(actions, input_vps, output_vps, vec![], &mut rng) + .unwrap(); (ptx, swap, intent_note) } @@ -102,9 +120,9 @@ pub fn consume_token_intent_ptx( offer: Token, output_auth_pk: pallas::Point, ) -> ShieldedPartialTransaction { - let (input_notes, output_notes) = swap.fill(&mut rng, intent_note, offer); + let (input_notes, [mut bought_note, mut returned_note]) = + swap.fill(&mut rng, intent_note, offer); let [intent_note, padding_input_note] = input_notes; - let [bought_note, returned_note] = output_notes; // output notes let output_auth = TokenAuthorization::new(output_auth_pk, *COMPRESSED_TOKEN_AUTH_VK); @@ -113,54 +131,70 @@ pub fn consume_token_intent_ptx( // Fetch a valid anchor for dummy notes let anchor = Anchor::from(pallas::Base::random(&mut rng)); - // Create the intent note proving info - let intent_note_proving_info = { - let intent_vp = PartialFulfillmentIntentValidityPredicateCircuit { - owned_note_pub_id: intent_note.get_nf().unwrap().inner(), - input_notes, - output_notes, - swap: swap.clone(), - }; - - InputNoteProvingInfo::new( + // Create action pairs + let actions = { + let action_1 = ActionInfo::new( intent_note, merkle_path.clone(), Some(anchor), - Box::new(intent_vp), - vec![], - ) + &mut bought_note, + &mut rng, + ); + + let action_2 = ActionInfo::new( + padding_input_note, + merkle_path, + Some(anchor), + &mut returned_note, + &mut rng, + ); + vec![action_1, action_2] }; - // Create the output note proving info - let bought_note_proving_info = TokenNote { - token_name: swap.buy.name().clone(), - note: bought_note, - } - .generate_output_token_note_proving_info(&mut rng, output_auth, input_notes, output_notes); - - // Create the padding input note proving info - let padding_input_note_proving_info = InputNoteProvingInfo::create_padding_note_proving_info( - padding_input_note, - merkle_path, - anchor, - input_notes, - output_notes, - ); + // Create VPs + let (input_vps, output_vps) = { + let output_notes = [bought_note, returned_note]; + // Create intent vps + let intent_vps = { + let intent_vp = PartialFulfillmentIntentValidityPredicateCircuit { + owned_note_pub_id: intent_note.get_nf().unwrap().inner(), + input_notes, + output_notes, + swap: swap.clone(), + }; + + NoteValidityPredicates::new(Box::new(intent_vp), vec![]) + }; - // Create the returned note proving info - let returned_note_proving_info = TokenNote { - token_name: swap.sell.token_name().clone(), - note: returned_note, - } - .generate_output_token_note_proving_info(&mut rng, output_auth, input_notes, output_notes); + // Create bought_note_vps + let bought_note_vps = TokenNote { + token_name: swap.buy.name().clone(), + note: bought_note, + } + .generate_output_token_vps(&mut rng, output_auth, input_notes, output_notes); + + // Create the padding input vps + let padding_input_vps = NoteValidityPredicates::create_input_padding_note_vps( + &padding_input_note, + input_notes, + output_notes, + ); + + // Create returned_note_vps + let returned_note_vps = TokenNote { + token_name: swap.sell.token_name().clone(), + note: returned_note, + } + .generate_output_token_vps(&mut rng, output_auth, input_notes, output_notes); + + ( + vec![intent_vps, padding_input_vps], + vec![bought_note_vps, returned_note_vps], + ) + }; // Create shielded partial tx - ShieldedPartialTransaction::build( - [intent_note_proving_info, padding_input_note_proving_info], - [bought_note_proving_info, returned_note_proving_info], - vec![], - &mut rng, - ) + ShieldedPartialTransaction::build(actions, input_vps, output_vps, vec![], &mut rng).unwrap() } pub fn create_token_swap_transaction(mut rng: R) -> Transaction { @@ -187,10 +221,10 @@ pub fn create_token_swap_transaction(mut rng: R) -> Tran &mut rng, offer.clone(), bob_auth_sk, - bob_nk, + bob_nk.get_nk().unwrap(), returned, bob_auth_pk, - bob_nk.to_commitment(), + bob_nk.get_commitment(), ); // Solver/Bob creates the partial transaction to consume the intent note diff --git a/taiga_halo2/examples/tx_examples/token.rs b/taiga_halo2/examples/tx_examples/token.rs index 79b8fb97..5a0cdba3 100644 --- a/taiga_halo2/examples/tx_examples/token.rs +++ b/taiga_halo2/examples/tx_examples/token.rs @@ -4,14 +4,14 @@ use pasta_curves::pallas; use rand::RngCore; use taiga_halo2::{ + action::ActionInfo, circuit::vp_examples::{ signature_verification::COMPRESSED_TOKEN_AUTH_VK, token::{Token, TokenAuthorization}, }, constant::TAIGA_COMMITMENT_TREE_DEPTH, merkle_tree::{Anchor, MerklePath}, - note::{InputNoteProvingInfo, Note, OutputNoteProvingInfo}, - nullifier::{Nullifier, NullifierKeyContainer}, + note::{Note, NoteValidityPredicates}, shielded_ptx::ShieldedPartialTransaction, }; @@ -20,76 +20,86 @@ pub fn create_token_swap_ptx( mut rng: R, input_token: Token, input_auth_sk: pallas::Scalar, - input_nk: NullifierKeyContainer, // NullifierKeyContainer::Key + input_nk: pallas::Base, output_token: Token, output_auth_pk: pallas::Point, - output_nk_com: NullifierKeyContainer, // NullifierKeyContainer::Commitment + output_nk_com: pallas::Base, ) -> ShieldedPartialTransaction { let input_auth = TokenAuthorization::from_sk_vk(&input_auth_sk, &COMPRESSED_TOKEN_AUTH_VK); // input note - let rho = Nullifier::from(pallas::Base::random(&mut rng)); - let input_note = input_token.create_random_token_note(&mut rng, rho, input_nk, &input_auth); + let input_note = input_token.create_random_input_token_note(&mut rng, input_nk, &input_auth); // output note - let input_note_nf = input_note.get_nf().unwrap(); let output_auth = TokenAuthorization::new(output_auth_pk, *COMPRESSED_TOKEN_AUTH_VK); - let output_note = - output_token.create_random_token_note(&mut rng, input_note_nf, output_nk_com, &output_auth); + let mut output_note = output_token.create_random_output_token_note(output_nk_com, &output_auth); // padding the zero notes - let padding_input_note = Note::random_padding_input_note(&mut rng); - let padding_input_note_nf = padding_input_note.get_nf().unwrap(); - let padding_output_note = Note::random_padding_output_note(&mut rng, padding_input_note_nf); - - let input_notes = [*input_note.note(), padding_input_note]; - let output_notes = [*output_note.note(), padding_output_note]; + let padding_input_note = Note::random_padding_note(&mut rng); + let mut padding_output_note = Note::random_padding_note(&mut rng); // Generate proving info let merkle_path = MerklePath::random(&mut rng, TAIGA_COMMITMENT_TREE_DEPTH); - // Fetch a valid anchor for padding input notes - let anchor = Anchor::from(pallas::Base::random(&mut rng)); + // Create action pairs + let actions = { + let action_1 = ActionInfo::new( + *input_note.note(), + merkle_path.clone(), + None, + &mut output_note.note, + &mut rng, + ); + + // Fetch a valid anchor for padding input notes + let anchor = Anchor::from(pallas::Base::random(&mut rng)); + let action_2 = ActionInfo::new( + padding_input_note, + merkle_path, + Some(anchor), + &mut padding_output_note, + &mut rng, + ); + vec![action_1, action_2] + }; + + // Create VPs + let (input_vps, output_vps) = { + let input_notes = [*input_note.note(), padding_input_note]; + let output_notes = [*output_note.note(), padding_output_note]; + // Create the input token vps + let input_token_vps = input_note.generate_input_token_vps( + &mut rng, + input_auth, + input_auth_sk, + input_notes, + output_notes, + ); - // Create the input note proving info - let input_note_proving_info = input_note.generate_input_token_note_proving_info( - &mut rng, - input_auth, - input_auth_sk, - merkle_path.clone(), - input_notes, - output_notes, - ); + // Create the output token vps + let output_token_vps = + output_note.generate_output_token_vps(&mut rng, output_auth, input_notes, output_notes); - // Create the output note proving info - let output_note_proving_info = output_note.generate_output_token_note_proving_info( - &mut rng, - output_auth, - input_notes, - output_notes, - ); + // Create the padding input vps + let padding_input_vps = NoteValidityPredicates::create_input_padding_note_vps( + &padding_input_note, + input_notes, + output_notes, + ); - // Create the padding input note proving info - let padding_input_note_proving_info = InputNoteProvingInfo::create_padding_note_proving_info( - padding_input_note, - merkle_path, - anchor, - input_notes, - output_notes, - ); + // Create the padding output vps + let padding_output_vps = NoteValidityPredicates::create_output_padding_note_vps( + &padding_output_note, + input_notes, + output_notes, + ); - // Create the padding output note proving info - let padding_output_note_proving_info = OutputNoteProvingInfo::create_padding_note_proving_info( - padding_output_note, - input_notes, - output_notes, - ); + ( + vec![input_token_vps, padding_input_vps], + vec![output_token_vps, padding_output_vps], + ) + }; // Create shielded partial tx - ShieldedPartialTransaction::build( - [input_note_proving_info, padding_input_note_proving_info], - [output_note_proving_info, padding_output_note_proving_info], - vec![], - &mut rng, - ) + ShieldedPartialTransaction::build(actions, input_vps, output_vps, vec![], &mut rng).unwrap() } 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 6d93c251..89d80343 100644 --- a/taiga_halo2/examples/tx_examples/token_swap_with_intent.rs +++ b/taiga_halo2/examples/tx_examples/token_swap_with_intent.rs @@ -9,6 +9,7 @@ use halo2_proofs::arithmetic::Field; use pasta_curves::{group::Curve, pallas}; use rand::{CryptoRng, RngCore}; use taiga_halo2::{ + action::ActionInfo, circuit::vp_examples::{ or_relation_intent::{create_intent_note, OrRelationIntentValidityPredicateCircuit}, signature_verification::COMPRESSED_TOKEN_AUTH_VK, @@ -16,8 +17,8 @@ use taiga_halo2::{ }, constant::TAIGA_COMMITMENT_TREE_DEPTH, merkle_tree::{Anchor, MerklePath}, - note::{InputNoteProvingInfo, Note, OutputNoteProvingInfo}, - nullifier::{Nullifier, NullifierKeyContainer}, + note::{Note, NoteValidityPredicates}, + nullifier::NullifierKeyContainer, shielded_ptx::ShieldedPartialTransaction, transaction::{ShieldedPartialTxBundle, Transaction, TransparentPartialTxBundle}, }; @@ -28,100 +29,114 @@ pub fn create_token_intent_ptx( token_2: Token, input_token: Token, input_auth_sk: pallas::Scalar, - input_nk: NullifierKeyContainer, // NullifierKeyContainer::Key + input_nk: pallas::Base, ) -> ( ShieldedPartialTransaction, - NullifierKeyContainer, pallas::Base, pallas::Base, - Nullifier, + pallas::Base, ) { let input_auth = TokenAuthorization::from_sk_vk(&input_auth_sk, &COMPRESSED_TOKEN_AUTH_VK); // input note - let rho = Nullifier::from(pallas::Base::random(&mut rng)); - let input_note = input_token.create_random_token_note(&mut rng, rho, input_nk, &input_auth); + let input_note = input_token.create_random_input_token_note(&mut rng, input_nk, &input_auth); // output intent note - 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( + let mut intent_note = create_intent_note( &mut rng, &token_1, &token_2, input_note_nk_com, input_note.app_data_dynamic, - input_note_nf, input_nk, ); // padding the zero notes - let padding_input_note = Note::random_padding_input_note(&mut rng); - let padding_input_note_nf = padding_input_note.get_nf().unwrap(); - let padding_output_note = Note::random_padding_output_note(&mut rng, padding_input_note_nf); - // Fetch a valid anchor for padding input notes - let anchor = Anchor::from(pallas::Base::random(&mut rng)); - - let input_notes = [*input_note.note(), padding_input_note]; - let output_notes = [intent_note, padding_output_note]; + let padding_input_note = Note::random_padding_note(&mut rng); + let mut padding_output_note = Note::random_padding_note(&mut rng); let merkle_path = MerklePath::random(&mut rng, TAIGA_COMMITMENT_TREE_DEPTH); - // Create the input note proving info - let input_note_proving_info = input_note.generate_input_token_note_proving_info( - &mut rng, - input_auth, - input_auth_sk, - merkle_path.clone(), - input_notes, - output_notes, - ); + // Create action pairs + let actions = { + let action_1 = ActionInfo::new( + *input_note.note(), + merkle_path.clone(), + None, + &mut intent_note, + &mut rng, + ); + + // Fetch a valid anchor for padding input notes + let anchor = Anchor::from(pallas::Base::random(&mut rng)); + let action_2 = ActionInfo::new( + padding_input_note, + merkle_path, + Some(anchor), + &mut padding_output_note, + &mut rng, + ); + vec![action_1, action_2] + }; - // Create the intent note proving info - let intent_note_proving_info = { - let intent_vp = OrRelationIntentValidityPredicateCircuit { - owned_note_pub_id: intent_note.commitment().inner(), + // Create VPs + let (input_vps, output_vps) = { + let input_notes = [*input_note.note(), padding_input_note]; + let output_notes = [intent_note, padding_output_note]; + // Create the input note vps + let input_note_vps = input_note.generate_input_token_vps( + &mut rng, + input_auth, + input_auth_sk, input_notes, output_notes, - token_1, - token_2, - receiver_nk_com: input_note_nk_com, - receiver_app_data_dynamic: input_note.app_data_dynamic, + ); + + // Create the intent note proving info + let intent_note_vps = { + let intent_vp = OrRelationIntentValidityPredicateCircuit { + owned_note_pub_id: intent_note.commitment().inner(), + input_notes, + output_notes, + token_1, + token_2, + receiver_nk_com: input_note_nk_com, + receiver_app_data_dynamic: input_note.app_data_dynamic, + }; + + NoteValidityPredicates::new(Box::new(intent_vp), vec![]) }; - OutputNoteProvingInfo::new(intent_note, Box::new(intent_vp), vec![]) - }; + // Create the padding input vps + let padding_input_vps = NoteValidityPredicates::create_input_padding_note_vps( + &padding_input_note, + input_notes, + output_notes, + ); - // Create the padding input note proving info - let padding_input_note_proving_info = InputNoteProvingInfo::create_padding_note_proving_info( - padding_input_note, - merkle_path, - anchor, - input_notes, - output_notes, - ); + // Create the padding output vps + let padding_output_vps = NoteValidityPredicates::create_output_padding_note_vps( + &padding_output_note, + input_notes, + output_notes, + ); - // Create the padding output note proving info - let padding_output_note_proving_info = OutputNoteProvingInfo::create_padding_note_proving_info( - padding_output_note, - input_notes, - output_notes, - ); + ( + vec![input_note_vps, padding_input_vps], + vec![intent_note_vps, padding_output_vps], + ) + }; // Create shielded partial tx - let ptx = ShieldedPartialTransaction::build( - [input_note_proving_info, padding_input_note_proving_info], - [intent_note_proving_info, padding_output_note_proving_info], - vec![], - &mut rng, - ); + let ptx = ShieldedPartialTransaction::build(actions, input_vps, output_vps, vec![], &mut rng) + .unwrap(); ( ptx, input_nk, input_note_nk_com, input_note.app_data_dynamic, - rho, ) } @@ -130,8 +145,7 @@ pub fn consume_token_intent_ptx( mut rng: R, token_1: Token, token_2: Token, - input_rho: Nullifier, - input_nk: NullifierKeyContainer, // NullifierKeyContainer::Key + input_nk: pallas::Base, receiver_nk_com: pallas::Base, receiver_app_data_dynamic: pallas::Base, output_token: Token, @@ -144,85 +158,89 @@ pub fn consume_token_intent_ptx( &token_2, receiver_nk_com, receiver_app_data_dynamic, - input_rho, input_nk, ); // output note let input_note_nf = intent_note.get_nf().unwrap(); let output_auth = TokenAuthorization::new(output_auth_pk, *COMPRESSED_TOKEN_AUTH_VK); - let output_note = output_token.create_random_token_note( - &mut rng, - input_note_nf, - input_nk.to_commitment(), - &output_auth, - ); + let output_nk_com = NullifierKeyContainer::from_key(input_nk).get_commitment(); + let mut output_note = output_token.create_random_output_token_note(output_nk_com, &output_auth); // padding the zero notes - let padding_input_note = Note::random_padding_input_note(&mut rng); - let padding_input_note_nf = padding_input_note.get_nf().unwrap(); - let padding_output_note = Note::random_padding_output_note(&mut rng, padding_input_note_nf); - - let input_notes = [intent_note, padding_input_note]; - let output_notes = [*output_note.note(), padding_output_note]; + let padding_input_note = Note::random_padding_note(&mut rng); + let mut padding_output_note = Note::random_padding_note(&mut rng); let merkle_path = MerklePath::random(&mut rng, TAIGA_COMMITMENT_TREE_DEPTH); // Fetch a valid anchor for dummy notes let anchor = Anchor::from(pallas::Base::random(&mut rng)); - // Create the intent note proving info - let intent_note_proving_info = { - let intent_vp = OrRelationIntentValidityPredicateCircuit { - owned_note_pub_id: input_note_nf.inner(), - input_notes, - output_notes, - token_1, - token_2, - receiver_nk_com, - receiver_app_data_dynamic, - }; - - InputNoteProvingInfo::new( + // Create action pairs + let actions = { + let action_1 = ActionInfo::new( intent_note, merkle_path.clone(), Some(anchor), - Box::new(intent_vp), - vec![], - ) + &mut output_note.note, + &mut rng, + ); + + let action_2 = ActionInfo::new( + padding_input_note, + merkle_path, + Some(anchor), + &mut padding_output_note, + &mut rng, + ); + vec![action_1, action_2] }; - // Create the output note proving info - let output_note_proving_info = output_note.generate_output_token_note_proving_info( - &mut rng, - output_auth, - input_notes, - output_notes, - ); + // Create VPs + let (input_vps, output_vps) = { + let input_notes = [intent_note, padding_input_note]; + let output_notes = [*output_note.note(), padding_output_note]; + // Create intent vps + let intent_vps = { + let intent_vp = OrRelationIntentValidityPredicateCircuit { + owned_note_pub_id: input_note_nf.inner(), + input_notes, + output_notes, + token_1, + token_2, + receiver_nk_com, + receiver_app_data_dynamic, + }; + + NoteValidityPredicates::new(Box::new(intent_vp), vec![]) + }; - // Create the padding input note proving info - let padding_input_note_proving_info = InputNoteProvingInfo::create_padding_note_proving_info( - padding_input_note, - merkle_path, - anchor, - input_notes, - output_notes, - ); + // Create the output token vps + let output_token_vps = + output_note.generate_output_token_vps(&mut rng, output_auth, input_notes, output_notes); - // Create the padding output note proving info - let padding_output_note_proving_info = OutputNoteProvingInfo::create_padding_note_proving_info( - padding_output_note, - input_notes, - output_notes, - ); + // Create the padding input vps + let padding_input_vps = NoteValidityPredicates::create_input_padding_note_vps( + &padding_input_note, + input_notes, + output_notes, + ); + + // Create the padding output vps + let padding_output_vps = NoteValidityPredicates::create_output_padding_note_vps( + &padding_output_note, + input_notes, + output_notes, + ); + + ( + vec![intent_vps, padding_input_vps], + vec![output_token_vps, padding_output_vps], + ) + }; // Create shielded partial tx - ShieldedPartialTransaction::build( - [intent_note_proving_info, padding_input_note_proving_info], - [output_note_proving_info, padding_output_note_proving_info], - vec![], - &mut rng, - ) + ShieldedPartialTransaction::build(actions, input_vps, output_vps, vec![], &mut rng).unwrap() } pub fn create_token_swap_intent_transaction(mut rng: R) -> Transaction { @@ -231,11 +249,11 @@ pub fn create_token_swap_intent_transaction(mut rng: R) // Alice creates the partial transaction with 5 BTC input and intent output let alice_auth_sk = pallas::Scalar::random(&mut rng); let alice_auth_pk = generator * alice_auth_sk; - let alice_nk = NullifierKeyContainer::random_key(&mut rng); + let alice_nk = pallas::Base::random(&mut rng); let token_1 = Token::new("dolphin".to_string(), 1u64); let token_2 = Token::new("monkey".to_string(), 2u64); let btc_token = Token::new("btc".to_string(), 5u64); - let (alice_ptx, intent_nk, receiver_nk_com, receiver_app_data_dynamic, intent_rho) = + let (alice_ptx, intent_nk, receiver_nk_com, receiver_app_data_dynamic) = create_token_intent_ptx( &mut rng, token_1.clone(), @@ -254,10 +272,10 @@ pub fn create_token_swap_intent_transaction(mut rng: R) &mut rng, token_1.clone(), bob_auth_sk, - bob_nk, + bob_nk.get_nk().unwrap(), btc_token, bob_auth_pk, - bob_nk.to_commitment(), + bob_nk.get_commitment(), ); // Solver/Bob creates the partial transaction to consume the intent note @@ -266,7 +284,6 @@ pub fn create_token_swap_intent_transaction(mut rng: R) &mut rng, token_1.clone(), token_2, - intent_rho, intent_nk, receiver_nk_com, receiver_app_data_dynamic, diff --git a/taiga_halo2/examples/tx_examples/token_swap_without_intent.rs b/taiga_halo2/examples/tx_examples/token_swap_without_intent.rs index b1d17e16..0712132d 100644 --- a/taiga_halo2/examples/tx_examples/token_swap_without_intent.rs +++ b/taiga_halo2/examples/tx_examples/token_swap_without_intent.rs @@ -30,10 +30,10 @@ pub fn create_token_swap_transaction(mut rng: R) -> Tran &mut rng, btc_token.clone(), alice_auth_sk, - alice_nk, + alice_nk.get_nk().unwrap(), eth_token.clone(), alice_auth_pk, - alice_nk.to_commitment(), + alice_nk.get_commitment(), ); // Bob creates the partial transaction @@ -45,10 +45,10 @@ pub fn create_token_swap_transaction(mut rng: R) -> Tran &mut rng, eth_token, bob_auth_sk, - bob_nk, + bob_nk.get_nk().unwrap(), xan_token.clone(), bob_auth_pk, - bob_nk.to_commitment(), + bob_nk.get_commitment(), ); // Carol creates the partial transaction @@ -60,10 +60,10 @@ pub fn create_token_swap_transaction(mut rng: R) -> Tran &mut rng, xan_token, carol_auth_sk, - carol_nk, + carol_nk.get_nk().unwrap(), btc_token, carol_auth_pk, - carol_nk.to_commitment(), + carol_nk.get_commitment(), ); // Solver creates the final transaction diff --git a/taiga_halo2/src/action.rs b/taiga_halo2/src/action.rs index c27a9578..56f34217 100644 --- a/taiga_halo2/src/action.rs +++ b/taiga_halo2/src/action.rs @@ -2,7 +2,7 @@ use crate::{ circuit::action_circuit::ActionCircuit, constant::{PRF_EXPAND_INPUT_VP_CM_R, PRF_EXPAND_OUTPUT_VP_CM_R}, merkle_tree::{Anchor, MerklePath}, - note::{InputNoteProvingInfo, Note, NoteCommitment, OutputNoteProvingInfo, RandomSeed}, + note::{Note, NoteCommitment, RandomSeed}, nullifier::Nullifier, value_commitment::ValueCommitment, vp_commitment::ValidityPredicateCommitment, @@ -116,34 +116,29 @@ impl BorshDeserialize for ActionPublicInputs { } impl ActionInfo { - pub fn new( + // The dummy input note must provide a valid custom_anchor, but a random merkle path + // The normal input note only needs to provide a valid merkle path. The anchor will be calculated from the note and path. + // The rho of output_note will be reset to the nullifier of input_note + pub fn new( input_note: Note, input_merkle_path: MerklePath, - input_anchor: Anchor, - output_note: Note, - rseed: RandomSeed, + custom_anchor: Option, + output_note: &mut Note, + mut rng: R, ) -> Self { + let input_anchor = match custom_anchor { + Some(anchor) => anchor, + None => input_note.calculate_root(&input_merkle_path), + }; + + output_note.set_rho(&input_note, &mut rng); + Self { input_note, input_merkle_path, input_anchor, - output_note, - rseed, - } - } - - pub fn from_proving_info( - input: InputNoteProvingInfo, - output: OutputNoteProvingInfo, - mut rng: R, - ) -> Self { - let rseed = RandomSeed::random(&mut rng); - Self { - input_note: input.note, - input_merkle_path: input.merkle_path, - input_anchor: input.anchor, - output_note: output.note, - rseed, + output_note: *output_note, + rseed: RandomSeed::random(&mut rng), } } @@ -209,22 +204,19 @@ pub mod tests { use super::ActionInfo; use crate::constant::TAIGA_COMMITMENT_TREE_DEPTH; use crate::merkle_tree::MerklePath; - use crate::note::tests::{random_input_note, random_output_note}; - use crate::note::RandomSeed; + use crate::note::tests::random_note; use rand::RngCore; pub fn random_action_info(mut rng: R) -> ActionInfo { - let input_note = random_input_note(&mut rng); - let output_note = random_output_note(&mut rng, input_note.get_nf().unwrap()); + let input_note = random_note(&mut rng); + let mut output_note = random_note(&mut rng); let input_merkle_path = MerklePath::random(&mut rng, TAIGA_COMMITMENT_TREE_DEPTH); - let input_anchor = input_note.calculate_root(&input_merkle_path); - let rseed = RandomSeed::random(&mut rng); ActionInfo::new( input_note, input_merkle_path, - input_anchor, - output_note, - rseed, + None, + &mut output_note, + &mut rng, ) } } diff --git a/taiga_halo2/src/circuit/vp_examples.rs b/taiga_halo2/src/circuit/vp_examples.rs index b63dadcb..764591fc 100644 --- a/taiga_halo2/src/circuit/vp_examples.rs +++ b/taiga_halo2/src/circuit/vp_examples.rs @@ -240,25 +240,15 @@ impl ValidityPredicateVerifyingInfo for TrivialValidityPredicateCircuit { #[cfg(test)] pub mod tests { use super::TrivialValidityPredicateCircuit; - use crate::{ - constant::NUM_NOTE, - note::tests::{random_input_note, random_output_note}, - }; + use crate::{constant::NUM_NOTE, note::tests::random_note}; use ff::Field; use pasta_curves::pallas; use rand::RngCore; pub fn random_trivial_vp_circuit(mut rng: R) -> TrivialValidityPredicateCircuit { let owned_note_pub_id = pallas::Base::random(&mut rng); - let input_notes = [(); NUM_NOTE].map(|_| random_input_note(&mut rng)); - let output_notes = input_notes - .iter() - .map(|input| random_output_note(&mut rng, input.get_nf().unwrap())) - .collect::>(); - TrivialValidityPredicateCircuit::new( - owned_note_pub_id, - input_notes, - output_notes.try_into().unwrap(), - ) + let input_notes = [(); NUM_NOTE].map(|_| random_note(&mut rng)); + let output_notes = [(); NUM_NOTE].map(|_| random_note(&mut rng)); + TrivialValidityPredicateCircuit::new(owned_note_pub_id, input_notes, output_notes) } #[test] diff --git a/taiga_halo2/src/circuit/vp_examples/cascade_intent.rs b/taiga_halo2/src/circuit/vp_examples/cascade_intent.rs index 6c6fa9d0..686aec0a 100644 --- a/taiga_halo2/src/circuit/vp_examples/cascade_intent.rs +++ b/taiga_halo2/src/circuit/vp_examples/cascade_intent.rs @@ -18,7 +18,7 @@ use crate::{ }, constant::{NUM_NOTE, SETUP_PARAMS_MAP}, note::{Note, RandomSeed}, - nullifier::{Nullifier, NullifierKeyContainer}, + nullifier::Nullifier, proof::Proof, vp_commitment::ValidityPredicateCommitment, vp_vk::ValidityPredicateVerifyingKey, @@ -150,13 +150,13 @@ vp_verifying_info_impl!(CascadeIntentValidityPredicateCircuit); pub fn create_intent_note( mut rng: R, cascade_note_cm: pallas::Base, - rho: Nullifier, - nk: NullifierKeyContainer, + nk: pallas::Base, ) -> Note { let app_data_static = CascadeIntentValidityPredicateCircuit::encode_app_data_static(cascade_note_cm); let rseed = RandomSeed::random(&mut rng); - Note::new( + let rho = Nullifier::random(&mut rng); + Note::new_input_note( *COMPRESSED_CASCADE_INTENT_VK, app_data_static, pallas::Base::zero(), @@ -171,28 +171,24 @@ pub fn create_intent_note( #[test] fn test_halo2_cascade_intent_vp_circuit() { use crate::constant::VP_CIRCUIT_PARAMS_SIZE; - use crate::note::tests::{random_input_note, random_output_note}; + use crate::note::tests::random_note; use halo2_proofs::arithmetic::Field; use halo2_proofs::dev::MockProver; use rand::rngs::OsRng; let mut rng = OsRng; let circuit = { - let cascade_input_note = random_input_note(&mut rng); + let cascade_input_note = random_note(&mut rng); let cascade_note_cm = cascade_input_note.commitment().inner(); - let rho = Nullifier::from(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); + let nk = pallas::Base::random(&mut rng); + let intent_note = create_intent_note(&mut rng, cascade_note_cm, nk); let input_notes = [intent_note, cascade_input_note]; - let output_notes = input_notes - .iter() - .map(|input| random_output_note(&mut rng, input.get_nf().unwrap())) - .collect::>(); + let output_notes = [(); NUM_NOTE].map(|_| random_note(&mut rng)); CascadeIntentValidityPredicateCircuit { owned_note_pub_id: input_notes[0].get_nf().unwrap().inner(), input_notes, - output_notes: output_notes.try_into().unwrap(), + output_notes, cascade_note_cm, } }; diff --git a/taiga_halo2/src/circuit/vp_examples/field_addition.rs b/taiga_halo2/src/circuit/vp_examples/field_addition.rs index d021cfed..90b77b2d 100644 --- a/taiga_halo2/src/circuit/vp_examples/field_addition.rs +++ b/taiga_halo2/src/circuit/vp_examples/field_addition.rs @@ -110,25 +110,22 @@ vp_verifying_info_impl!(FieldAdditionValidityPredicateCircuit); #[test] fn test_halo2_addition_vp_circuit() { use crate::constant::VP_CIRCUIT_PARAMS_SIZE; - use crate::note::tests::{random_input_note, random_output_note}; + use crate::note::tests::random_note; use halo2_proofs::arithmetic::Field; use halo2_proofs::dev::MockProver; use rand::rngs::OsRng; let mut rng = OsRng; let circuit = { - let input_notes = [(); NUM_NOTE].map(|_| random_input_note(&mut rng)); - let output_notes = input_notes - .iter() - .map(|input| random_output_note(&mut rng, input.get_nf().unwrap())) - .collect::>(); + let input_notes = [(); NUM_NOTE].map(|_| random_note(&mut rng)); + let output_notes = [(); NUM_NOTE].map(|_| random_note(&mut rng)); let a = pallas::Base::random(&mut rng); let b = pallas::Base::random(&mut rng); let owned_note_pub_id = pallas::Base::random(&mut rng); FieldAdditionValidityPredicateCircuit { owned_note_pub_id, input_notes, - output_notes: output_notes.try_into().unwrap(), + output_notes, a, b, } 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 4320540b..efbdb533 100644 --- a/taiga_halo2/src/circuit/vp_examples/or_relation_intent.rs +++ b/taiga_halo2/src/circuit/vp_examples/or_relation_intent.rs @@ -18,7 +18,7 @@ use crate::{ }, constant::{NUM_NOTE, SETUP_PARAMS_MAP}, note::{Note, RandomSeed}, - nullifier::{Nullifier, NullifierKeyContainer}, + nullifier::Nullifier, proof::Proof, utils::poseidon_hash_n, vp_commitment::ValidityPredicateCommitment, @@ -280,8 +280,7 @@ pub fn create_intent_note( token_2: &Token, receiver_nk_com: pallas::Base, receiver_app_data_dynamic: pallas::Base, - rho: Nullifier, - nk: NullifierKeyContainer, + nk: pallas::Base, ) -> Note { let app_data_static = OrRelationIntentValidityPredicateCircuit::encode_app_data_static( token_1, @@ -290,7 +289,8 @@ pub fn create_intent_note( receiver_app_data_dynamic, ); let rseed = RandomSeed::random(&mut rng); - Note::new( + let rho = Nullifier::random(&mut rng); + Note::new_input_note( *COMPRESSED_OR_RELATION_INTENT_VK, app_data_static, pallas::Base::zero(), @@ -305,28 +305,21 @@ pub fn create_intent_note( #[test] fn test_halo2_or_relation_intent_vp_circuit() { use crate::constant::VP_CIRCUIT_PARAMS_SIZE; - use crate::{ - circuit::vp_examples::token::COMPRESSED_TOKEN_VK, note::tests::random_output_note, - nullifier::tests::random_nullifier, - }; + use crate::{circuit::vp_examples::token::COMPRESSED_TOKEN_VK, note::tests::random_note}; use halo2_proofs::arithmetic::Field; use halo2_proofs::dev::MockProver; use rand::rngs::OsRng; let mut rng = OsRng; let circuit = { - let mut output_notes = [(); NUM_NOTE].map(|_| { - let padding_rho = random_nullifier(&mut rng); - random_output_note(&mut rng, padding_rho) - }); + let mut output_notes = [(); NUM_NOTE].map(|_| random_note(&mut rng)); let token_1 = Token::new("token1".to_string(), 1u64); let token_2 = Token::new("token2".to_string(), 2u64); output_notes[0].note_type.app_vk = *COMPRESSED_TOKEN_VK; output_notes[0].note_type.app_data_static = token_1.encode_name(); output_notes[0].value = token_1.value(); - let rho = Nullifier::from(pallas::Base::random(&mut rng)); - let nk = NullifierKeyContainer::random_key(&mut rng); + let nk = pallas::Base::random(&mut rng); let nk_com = output_notes[0].get_nk_commitment(); let intent_note = create_intent_note( &mut rng, @@ -334,10 +327,9 @@ fn test_halo2_or_relation_intent_vp_circuit() { &token_2, nk_com, output_notes[0].app_data_dynamic, - rho, nk, ); - let padding_input_note = Note::random_padding_input_note(&mut rng); + let padding_input_note = Note::random_padding_note(&mut rng); let input_notes = [intent_note, padding_input_note]; OrRelationIntentValidityPredicateCircuit { owned_note_pub_id: input_notes[0].get_nf().unwrap().inner(), 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 682c0bcf..b1700a9d 100644 --- a/taiga_halo2/src/circuit/vp_examples/partial_fulfillment_intent.rs +++ b/taiga_halo2/src/circuit/vp_examples/partial_fulfillment_intent.rs @@ -206,8 +206,6 @@ mod tests { #[test] fn create_intent() { - use crate::nullifier::Nullifier; - let mut rng = OsRng; let sell = Token::new("token1".to_string(), 2u64); let buy = Token::new("token2".to_string(), 4u64); @@ -215,9 +213,8 @@ mod tests { let swap = swap(&mut rng, sell, buy); let intent_note = swap.create_intent_note(&mut rng); - let input_padding_note = Note::random_padding_input_note(&mut rng); - let nf = Nullifier::random(&mut rng); - let output_padding_note = Note::random_padding_output_note(&mut rng, nf); + let input_padding_note = Note::random_padding_note(&mut rng); + let output_padding_note = Note::random_padding_note(&mut rng); let input_notes = [*swap.sell.note(), input_padding_note]; let output_notes = [intent_note, output_padding_note]; diff --git a/taiga_halo2/src/circuit/vp_examples/partial_fulfillment_intent/swap.rs b/taiga_halo2/src/circuit/vp_examples/partial_fulfillment_intent/swap.rs index 1f8e82ae..40db7c9a 100644 --- a/taiga_halo2/src/circuit/vp_examples/partial_fulfillment_intent/swap.rs +++ b/taiga_halo2/src/circuit/vp_examples/partial_fulfillment_intent/swap.rs @@ -6,9 +6,9 @@ use crate::{ }, constant::NUM_NOTE, note::{Note, RandomSeed}, - nullifier::{Nullifier, NullifierKeyContainer}, utils::poseidon_hash_n, }; +use halo2_proofs::arithmetic::Field; use halo2_proofs::{ circuit::{Layouter, Value}, plonk::{Advice, Column, Error}, @@ -33,9 +33,8 @@ impl Swap { assert_eq!(buy.value() % sell.value(), 0); let sell = { - let rho = Nullifier::random(&mut rng); - let nk = NullifierKeyContainer::random_key(&mut rng); - sell.create_random_token_note(&mut rng, rho, nk, &auth) + let nk = pallas::Base::random(&mut rng); + sell.create_random_input_token_note(&mut rng, nk, &auth) }; Swap { sell, buy, auth } @@ -56,14 +55,12 @@ impl Swap { let ratio = self.buy.value() / self.sell.value; assert_eq!(offer.value() % ratio, 0); - let offer_note = offer.create_random_token_note( - &mut rng, - intent_note.get_nf().unwrap(), - self.sell.note().nk_container, + let offer_note = offer.create_random_output_token_note( + self.sell.note().nk_container.get_commitment(), &self.auth, ); - let input_padding_note = Note::random_padding_input_note(&mut rng); + let input_padding_note = Note::random_padding_note(&mut rng); let returned_note = if offer.value() < self.buy.value() { let filled_value = offer.value() / ratio; @@ -71,15 +68,13 @@ impl Swap { let returned_token = Token::new(self.sell.token_name().inner().to_string(), returned_value); *returned_token - .create_random_token_note( - &mut rng, - input_padding_note.get_nf().unwrap(), - self.sell.note().nk_container, + .create_random_output_token_note( + self.sell.note().nk_container.get_commitment(), &self.auth, ) .note() } else { - Note::random_padding_output_note(&mut rng, input_padding_note.get_nf().unwrap()) + Note::random_padding_note(&mut rng) }; let input_notes = [intent_note, input_padding_note]; @@ -104,12 +99,12 @@ impl Swap { pub fn create_intent_note(&self, mut rng: R) -> Note { let rseed = RandomSeed::random(&mut rng); - Note::new( + Note::new_input_note( *COMPRESSED_PARTIAL_FULFILLMENT_INTENT_VK, self.encode_app_data_static(), pallas::Base::zero(), 1u64, - self.sell.note().nk_container, + self.sell.note().nk_container.get_nk().unwrap(), self.sell.note().get_nf().unwrap(), false, rseed, diff --git a/taiga_halo2/src/circuit/vp_examples/receiver_vp.rs b/taiga_halo2/src/circuit/vp_examples/receiver_vp.rs index 7c5afd1a..7990344d 100644 --- a/taiga_halo2/src/circuit/vp_examples/receiver_vp.rs +++ b/taiga_halo2/src/circuit/vp_examples/receiver_vp.rs @@ -285,21 +285,15 @@ vp_verifying_info_impl!(ReceiverValidityPredicateCircuit); #[test] fn test_halo2_receiver_vp_circuit() { use crate::constant::VP_CIRCUIT_PARAMS_SIZE; - use crate::{ - note::tests::{random_input_note, random_output_note}, - utils::poseidon_hash_n, - }; + use crate::{note::tests::random_note, utils::poseidon_hash_n}; use ff::{Field, PrimeField}; use halo2_proofs::dev::MockProver; use rand::rngs::OsRng; let mut rng = OsRng; let (circuit, rcv_sk) = { - let input_notes = [(); NUM_NOTE].map(|_| random_input_note(&mut rng)); - let mut output_notes = input_notes - .iter() - .map(|input| random_output_note(&mut rng, input.get_nf().unwrap())) - .collect::>(); + let input_notes = [(); NUM_NOTE].map(|_| random_note(&mut rng)); + let mut output_notes = [(); NUM_NOTE].map(|_| random_note(&mut rng)); let nonce = pallas::Base::from_u128(23333u128); let sk = pallas::Base::random(&mut rng); let rcv_sk = pallas::Base::random(&mut rng); @@ -317,7 +311,7 @@ fn test_halo2_receiver_vp_circuit() { ReceiverValidityPredicateCircuit { owned_note_pub_id, input_notes, - output_notes: output_notes.try_into().unwrap(), + output_notes, vp_vk: *COMPRESSED_RECEIVER_VK, nonce, sk, diff --git a/taiga_halo2/src/circuit/vp_examples/signature_verification.rs b/taiga_halo2/src/circuit/vp_examples/signature_verification.rs index 0677cc77..004a9509 100644 --- a/taiga_halo2/src/circuit/vp_examples/signature_verification.rs +++ b/taiga_halo2/src/circuit/vp_examples/signature_verification.rs @@ -295,17 +295,14 @@ fn test_halo2_sig_verification_vp_circuit() { receiver_vp::COMPRESSED_RECEIVER_VK, token::TokenAuthorization, }; use crate::constant::VP_CIRCUIT_PARAMS_SIZE; - use crate::note::tests::{random_input_note, random_output_note}; + use crate::note::tests::random_note; use halo2_proofs::dev::MockProver; use rand::rngs::OsRng; let mut rng = OsRng; let circuit = { - let mut input_notes = [(); NUM_NOTE].map(|_| random_input_note(&mut rng)); - let output_notes = input_notes - .iter() - .map(|input| random_output_note(&mut rng, input.get_nf().unwrap())) - .collect::>(); + let mut input_notes = [(); NUM_NOTE].map(|_| random_note(&mut rng)); + let output_notes = [(); NUM_NOTE].map(|_| random_note(&mut rng)); let sk = pallas::Scalar::random(&mut rng); let auth_vk = pallas::Base::random(&mut rng); let auth = TokenAuthorization::from_sk_vk(&sk, &auth_vk); @@ -315,7 +312,7 @@ fn test_halo2_sig_verification_vp_circuit() { &mut rng, owned_note_pub_id, input_notes, - output_notes.try_into().unwrap(), + output_notes, auth_vk, sk, *COMPRESSED_RECEIVER_VK, diff --git a/taiga_halo2/src/circuit/vp_examples/token.rs b/taiga_halo2/src/circuit/vp_examples/token.rs index dead3b84..59ec34bb 100644 --- a/taiga_halo2/src/circuit/vp_examples/token.rs +++ b/taiga_halo2/src/circuit/vp_examples/token.rs @@ -20,9 +20,8 @@ use crate::{ VP_CIRCUIT_FIRST_DYNAMIC_VP_CM_2, VP_CIRCUIT_SECOND_DYNAMIC_VP_CM_1, VP_CIRCUIT_SECOND_DYNAMIC_VP_CM_2, }, - merkle_tree::MerklePath, - note::{InputNoteProvingInfo, Note, OutputNoteProvingInfo, RandomSeed}, - nullifier::{Nullifier, NullifierKeyContainer}, + note::{Note, NoteValidityPredicates, RandomSeed}, + nullifier::Nullifier, proof::Proof, utils::poseidon_hash_n, vp_commitment::ValidityPredicateCommitment, @@ -92,22 +91,22 @@ impl Token { pallas::Base::from(self.value) } - pub fn create_random_token_note( + pub fn create_random_input_token_note( &self, mut rng: R, - rho: Nullifier, - nk_container: NullifierKeyContainer, + nk: pallas::Base, auth: &TokenAuthorization, ) -> TokenNote { let app_data_static = self.encode_name(); let app_data_dynamic = auth.to_app_data_dynamic(); let rseed = RandomSeed::random(&mut rng); - let note = Note::new( + let rho = Nullifier::random(&mut rng); + let note = Note::new_input_note( *COMPRESSED_TOKEN_VK, app_data_static, app_data_dynamic, self.value(), - nk_container, + nk, rho, true, rseed, @@ -118,6 +117,28 @@ impl Token { note, } } + + pub fn create_random_output_token_note( + &self, + nk_com: pallas::Base, + auth: &TokenAuthorization, + ) -> TokenNote { + let app_data_static = self.encode_name(); + let app_data_dynamic = auth.to_app_data_dynamic(); + let note = Note::new_output_note( + *COMPRESSED_TOKEN_VK, + app_data_static, + app_data_dynamic, + self.value(), + nk_com, + true, + ); + + TokenNote { + token_name: self.name().clone(), + note, + } + } } #[derive(Clone, Debug, Default)] @@ -151,16 +172,14 @@ impl TokenNote { &self.note } - #[allow(clippy::too_many_arguments)] - pub fn generate_input_token_note_proving_info( + pub fn generate_input_token_vps( &self, mut rng: R, auth: TokenAuthorization, auth_sk: pallas::Scalar, - merkle_path: MerklePath, input_notes: [Note; NUM_NOTE], output_notes: [Note; NUM_NOTE], - ) -> InputNoteProvingInfo { + ) -> NoteValidityPredicates { let TokenNote { token_name, note } = self; // token VP let nf = note.get_nf().unwrap().inner(); @@ -185,23 +204,16 @@ impl TokenNote { *COMPRESSED_RECEIVER_VK, ); - // input note proving info - InputNoteProvingInfo::new( - *note, - merkle_path, - None, - Box::new(token_vp), - vec![Box::new(token_auth_vp)], - ) + NoteValidityPredicates::new(Box::new(token_vp), vec![Box::new(token_auth_vp)]) } - pub fn generate_output_token_note_proving_info( + pub fn generate_output_token_vps( &self, mut rng: R, auth: TokenAuthorization, input_notes: [Note; NUM_NOTE], output_notes: [Note; NUM_NOTE], - ) -> OutputNoteProvingInfo { + ) -> NoteValidityPredicates { let TokenNote { token_name, note } = self; let owned_note_pub_id = note.commitment().inner(); @@ -228,7 +240,7 @@ impl TokenNote { auth_vp_vk: *COMPRESSED_TOKEN_AUTH_VK, }; - OutputNoteProvingInfo::new(*note, Box::new(token_vp), vec![Box::new(receiver_vp)]) + NoteValidityPredicates::new(Box::new(token_vp), vec![Box::new(receiver_vp)]) } } @@ -521,17 +533,14 @@ impl TokenAuthorization { #[test] fn test_halo2_token_vp_circuit() { use crate::constant::VP_CIRCUIT_PARAMS_SIZE; - use crate::note::tests::{random_input_note, random_output_note}; + use crate::note::tests::random_note; use halo2_proofs::dev::MockProver; use rand::rngs::OsRng; let mut rng = OsRng; let circuit = { - let mut input_notes = [(); NUM_NOTE].map(|_| random_input_note(&mut rng)); - let output_notes = input_notes - .iter() - .map(|input| random_output_note(&mut rng, input.get_nf().unwrap())) - .collect::>(); + let mut input_notes = [(); NUM_NOTE].map(|_| random_note(&mut rng)); + let output_notes = [(); NUM_NOTE].map(|_| random_note(&mut rng)); let token_name = TokenName("Token_name".to_string()); let auth = TokenAuthorization::random(&mut rng); input_notes[0].note_type.app_data_static = token_name.encode(); @@ -539,7 +548,7 @@ fn test_halo2_token_vp_circuit() { TokenValidityPredicateCircuit { owned_note_pub_id: input_notes[0].get_nf().unwrap().inner(), input_notes, - output_notes: output_notes.try_into().unwrap(), + output_notes, token_name, auth, receiver_vp_vk: *COMPRESSED_RECEIVER_VK, diff --git a/taiga_halo2/src/note.rs b/taiga_halo2/src/note.rs index 35f29b33..779820cf 100644 --- a/taiga_halo2/src/note.rs +++ b/taiga_halo2/src/note.rs @@ -9,6 +9,7 @@ use crate::{ }, merkle_tree::{Anchor, MerklePath, Node}, nullifier::{Nullifier, NullifierKeyContainer}, + shielded_ptx::NoteVPVerifyingInfoSet, utils::{poseidon_hash_n, poseidon_to_curve}, }; use blake2b_simd::Params as Blake2bParams; @@ -122,30 +123,21 @@ pub struct NoteType { #[derive(Copy, Clone, Debug, Default)] pub struct RandomSeed([u8; 32]); +/// NoteValidityPredicates includes one application(static) VP and a few dynamic VPs. #[derive(Clone)] -pub struct InputNoteProvingInfo { - pub note: Note, - pub merkle_path: MerklePath, - pub anchor: Anchor, - application_vp: Box, - dynamic_vps: Vec>, -} - -#[derive(Clone)] -pub struct OutputNoteProvingInfo { - pub note: Note, +pub struct NoteValidityPredicates { application_vp: Box, dynamic_vps: Vec>, } impl Note { #[allow(clippy::too_many_arguments)] - pub fn new( + pub fn new_input_note( app_vk: pallas::Base, app_data_static: pallas::Base, app_data_dynamic: pallas::Base, value: u64, - nk_container: NullifierKeyContainer, + nk: pallas::Base, rho: Nullifier, is_merkle_checked: bool, rseed: RandomSeed, @@ -155,7 +147,7 @@ impl Note { note_type, app_data_dynamic, value, - nk_container, + nk_container: NullifierKeyContainer::Key(nk), is_merkle_checked, psi: rseed.get_psi(&rho), rcm: rseed.get_rcm(&rho), @@ -163,6 +155,29 @@ impl Note { } } + // The rho, psi, and rcm are not specified until the action is constructed. + #[allow(clippy::too_many_arguments)] + pub fn new_output_note( + app_vk: pallas::Base, + app_data_static: pallas::Base, + app_data_dynamic: pallas::Base, + value: u64, + nk_com: pallas::Base, + is_merkle_checked: bool, + ) -> Self { + let note_type = NoteType::new(app_vk, app_data_static); + Self { + note_type, + app_data_dynamic, + value, + nk_container: NullifierKeyContainer::Commitment(nk_com), + is_merkle_checked, + psi: pallas::Base::default(), + rcm: pallas::Base::default(), + rho: Nullifier::default(), + } + } + #[allow(clippy::too_many_arguments)] pub fn from_full( app_vk: pallas::Base, @@ -188,7 +203,7 @@ impl Note { } } - pub fn random_padding_input_note(mut rng: R) -> Self { + pub fn random_padding_note(mut rng: R) -> Self { let app_vk = *COMPRESSED_TRIVIAL_VP_VK; let app_data_static = pallas::Base::random(&mut rng); let note_type = NoteType::new(app_vk, app_data_static); @@ -208,25 +223,6 @@ impl Note { } } - pub fn random_padding_output_note(mut rng: R, rho: Nullifier) -> Self { - let app_vk = *COMPRESSED_TRIVIAL_VP_VK; - let app_data_static = pallas::Base::random(&mut rng); - let note_type = NoteType::new(app_vk, app_data_static); - let app_data_dynamic = pallas::Base::random(&mut rng); - let nk_com = NullifierKeyContainer::from_commitment(pallas::Base::random(&mut rng)); - let rseed = RandomSeed::random(&mut rng); - Note { - note_type, - app_data_dynamic, - value: 0, - nk_container: nk_com, - rho, - psi: rseed.get_psi(&rho), - rcm: rseed.get_rcm(&rho), - is_merkle_checked: false, - } - } - // 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 compose_is_merkle_checked_value = if self.is_merkle_checked { @@ -288,6 +284,14 @@ impl Note { let cm_node = Node::from(self); path.root(cm_node) } + + pub fn set_rho(&mut self, input_note: &Note, mut rng: R) { + let rseed = RandomSeed::random(&mut rng); + + self.rho = input_note.get_nf().unwrap(); + self.psi = rseed.get_psi(&self.rho); + self.rcm = rseed.get_rcm(&self.rho); + } } #[cfg(feature = "borsh")] @@ -494,96 +498,71 @@ impl RandomSeed { } } -impl InputNoteProvingInfo { +impl NoteValidityPredicates { pub fn new( - note: Note, - merkle_path: MerklePath, - // If no custom anchor is provided then the standard one is calculated from the note and path. - custom_anchor: Option, application_vp: Box, dynamic_vps: Vec>, ) -> Self { - let anchor = match custom_anchor { - Some(anchor) => anchor, - None => note.calculate_root(&merkle_path), - }; Self { - note, - merkle_path, - anchor, application_vp, dynamic_vps, } } - pub fn get_application_vp(&self) -> Box { - self.application_vp.clone() - } + // Generate vp proofs + pub fn build(&self) -> NoteVPVerifyingInfoSet { + let app_vp_verifying_info = self.application_vp.get_verifying_info(); - pub fn get_dynamic_vps(&self) -> Vec> { - self.dynamic_vps.clone() + let app_dynamic_vp_verifying_info = self + .dynamic_vps + .iter() + .map(|verifying_info| verifying_info.get_verifying_info()) + .collect(); + + NoteVPVerifyingInfoSet::new(app_vp_verifying_info, app_dynamic_vp_verifying_info) } - pub fn create_padding_note_proving_info( - padding_note: Note, - merkle_path: MerklePath, - anchor: Anchor, + // Create an input padding note vps + pub fn create_input_padding_note_vps( + note: &Note, input_notes: [Note; NUM_NOTE], output_notes: [Note; NUM_NOTE], ) -> Self { - let trivail_vp = Box::new(TrivialValidityPredicateCircuit { - owned_note_pub_id: padding_note.get_nf().unwrap().inner(), + let note_id = note.get_nf().unwrap().inner(); + let application_vp = Box::new(TrivialValidityPredicateCircuit::new( + note_id, input_notes, output_notes, - }); - InputNoteProvingInfo::new(padding_note, merkle_path, Some(anchor), trivail_vp, vec![]) - } -} - -impl OutputNoteProvingInfo { - pub fn new( - note: Note, - application_vp: Box, - dynamic_vps: Vec>, - ) -> Self { + )); Self { - note, application_vp, - dynamic_vps, + dynamic_vps: vec![], } } - pub fn get_application_vp(&self) -> Box { - self.application_vp.clone() - } - - pub fn get_dynamic_vps(&self) -> Vec> { - self.dynamic_vps.clone() - } - - pub fn create_padding_note_proving_info( - padding_note: Note, + // Create an output padding note vps + pub fn create_output_padding_note_vps( + note: &Note, input_notes: [Note; NUM_NOTE], output_notes: [Note; NUM_NOTE], ) -> Self { - let trivail_vp = Box::new(TrivialValidityPredicateCircuit { - owned_note_pub_id: padding_note.commitment().inner(), + let note_id = note.commitment().inner(); + let application_vp = Box::new(TrivialValidityPredicateCircuit::new( + note_id, input_notes, output_notes, - }); - OutputNoteProvingInfo::new(padding_note, trivail_vp, vec![]) + )); + Self { + application_vp, + dynamic_vps: vec![], + } } } #[cfg(test)] pub mod tests { - use super::{InputNoteProvingInfo, Note, NoteType, OutputNoteProvingInfo, RandomSeed}; - use crate::{ - circuit::vp_examples::tests::random_trivial_vp_circuit, - constant::TAIGA_COMMITMENT_TREE_DEPTH, - merkle_tree::MerklePath, - nullifier::{tests::*, Nullifier, NullifierKeyContainer}, - }; + use super::{Note, NoteType, RandomSeed}; + use crate::nullifier::tests::*; use halo2_proofs::arithmetic::Field; use pasta_curves::pallas; use rand::{Rng, RngCore}; @@ -594,31 +573,14 @@ pub mod tests { NoteType::new(app_vk, app_data_static) } - pub fn random_input_note(mut rng: R) -> Note { + pub fn random_note(mut rng: R) -> Note { let rho = random_nullifier(&mut rng); - let nk = random_nullifier_key(&mut rng); - random_note_from_parts(&mut rng, rho, nk) - } - - pub fn random_output_note(mut rng: R, rho: Nullifier) -> Note { - let nk_com = random_nullifier_key_commitment(&mut rng); - random_note_from_parts(&mut rng, rho, nk_com) - } - - fn random_note_from_parts( - mut rng: R, - rho: Nullifier, - nk_container: NullifierKeyContainer, - ) -> Note { - let note_type = random_note_type(&mut rng); - let app_data_dynamic = pallas::Base::random(&mut rng); - let value: u64 = rng.gen(); let rseed = RandomSeed::random(&mut rng); Note { - note_type, - app_data_dynamic, - value, - nk_container, + note_type: random_note_type(&mut rng), + app_data_dynamic: pallas::Base::random(&mut rng), + value: rng.gen(), + nk_container: random_nullifier_key(&mut rng), is_merkle_checked: true, psi: rseed.get_psi(&rho), rcm: rseed.get_rcm(&rho), @@ -626,28 +588,6 @@ pub mod tests { } } - pub fn random_input_proving_info(mut rng: R) -> InputNoteProvingInfo { - let note = random_input_note(&mut rng); - let merkle_path = MerklePath::random(&mut rng, TAIGA_COMMITMENT_TREE_DEPTH); - let application_vp = Box::new(random_trivial_vp_circuit(&mut rng)); - let dynamic_vps = vec![]; - InputNoteProvingInfo::new(note, merkle_path, None, application_vp, dynamic_vps) - } - - pub fn random_output_proving_info( - mut rng: R, - rho: Nullifier, - ) -> OutputNoteProvingInfo { - let note = random_output_note(&mut rng, rho); - let application_vp = Box::new(random_trivial_vp_circuit(&mut rng)); - let dynamic_vps = vec![]; - OutputNoteProvingInfo { - note, - application_vp, - dynamic_vps, - } - } - #[cfg(feature = "borsh")] #[test] fn note_borsh_serialization_test() { @@ -657,7 +597,7 @@ pub mod tests { use crate::note::NoteCommitment; let mut rng = OsRng; - let input_note = random_input_note(&mut rng); + let input_note = random_note(&mut rng); { // BorshSerialize let borsh = borsh::to_vec(&input_note).unwrap(); @@ -666,8 +606,9 @@ pub mod tests { assert_eq!(input_note, de_note); } - let output_note = random_output_note(&mut rng, input_note.rho); + let mut output_note = input_note; { + output_note.nk_container = random_nullifier_key_commitment(&mut rng); // BorshSerialize let borsh = borsh::to_vec(&output_note).unwrap(); // BorshDeserialize diff --git a/taiga_halo2/src/shielded_ptx.rs b/taiga_halo2/src/shielded_ptx.rs index 1316173f..78ac3f86 100644 --- a/taiga_halo2/src/shielded_ptx.rs +++ b/taiga_halo2/src/shielded_ptx.rs @@ -7,7 +7,7 @@ use crate::constant::{ use crate::error::TransactionError; use crate::executable::Executable; use crate::merkle_tree::Anchor; -use crate::note::{InputNoteProvingInfo, NoteCommitment, OutputNoteProvingInfo}; +use crate::note::{NoteCommitment, NoteValidityPredicates}; use crate::nullifier::Nullifier; use crate::proof::Proof; use crate::value_commitment::ValueCommitment; @@ -91,7 +91,7 @@ impl ShieldedPartialTransaction { .collect(); let mut rcv_sum = pallas::Scalar::zero(); let actions: Vec = actions - .into_iter() + .iter() .map(|action_info| { rcv_sum += action_info.get_rcv(); ActionVerifyingInfo::create(action_info, &mut rng).unwrap() @@ -108,47 +108,41 @@ impl ShieldedPartialTransaction { } pub fn build( - input_info: [InputNoteProvingInfo; NUM_NOTE], - output_info: [OutputNoteProvingInfo; NUM_NOTE], + action_pairs: Vec, + input_note_vps: Vec, + output_note_vps: Vec, hints: Vec, mut rng: R, - ) -> Self { - let inputs: Vec = input_info + ) -> Result { + // Generate action proofs + let mut rcv_sum = pallas::Scalar::zero(); + let actions: Vec = action_pairs .iter() - .map(|input_note| { - NoteVPVerifyingInfoSet::build( - input_note.get_application_vp(), - input_note.get_dynamic_vps(), - ) + .map(|action_info| { + rcv_sum += action_info.get_rcv(); + ActionVerifyingInfo::create(action_info, &mut rng).unwrap() }) .collect(); - let outputs: Vec = output_info + + // Generate input vp proofs + let inputs: Vec = input_note_vps .iter() - .map(|output_note| { - NoteVPVerifyingInfoSet::build( - output_note.get_application_vp(), - output_note.get_dynamic_vps(), - ) - }) + .map(|input_note_vp| input_note_vp.build()) .collect(); - let mut rcv_sum = pallas::Scalar::zero(); - let actions: Vec = input_info - .into_iter() - .zip(output_info) - .map(|(input, output)| { - let action_info = ActionInfo::from_proving_info(input, output, &mut rng); - rcv_sum += action_info.get_rcv(); - ActionVerifyingInfo::create(action_info, &mut rng).unwrap() - }) + + // Generate output vp proofs + let outputs: Vec = output_note_vps + .iter() + .map(|output_note_vp| output_note_vp.build()) .collect(); - Self { + Ok(Self { actions: actions.try_into().unwrap(), inputs: inputs.try_into().unwrap(), outputs: outputs.try_into().unwrap(), binding_sig_r: Some(rcv_sum), hints, - } + }) } // verify zk proof @@ -400,7 +394,7 @@ impl<'a> Decoder<'a> for ShieldedPartialTransaction { } impl ActionVerifyingInfo { - pub fn create(action_info: ActionInfo, mut rng: R) -> Result { + pub fn create(action_info: &ActionInfo, mut rng: R) -> Result { let (action_instance, circuit) = action_info.build(); let params = SETUP_PARAMS_MAP.get(&ACTION_CIRCUIT_PARAMS_SIZE).unwrap(); let action_proof = Proof::create( @@ -409,8 +403,7 @@ impl ActionVerifyingInfo { circuit, &[&action_instance.to_instance()], &mut rng, - ) - .unwrap(); + )?; Ok(Self { action_proof, action_instance, @@ -440,6 +433,7 @@ impl NoteVPVerifyingInfoSet { } } + // TODO: remove it. pub fn build( application_vp: Box, dynamic_vps: Vec>, @@ -493,12 +487,13 @@ impl NoteVPVerifyingInfoSet { #[cfg(test)] pub mod testing { use crate::{ + action::ActionInfo, circuit::vp_circuit::{ValidityPredicate, ValidityPredicateVerifyingInfo}, circuit::vp_examples::TrivialValidityPredicateCircuit, constant::TAIGA_COMMITMENT_TREE_DEPTH, merkle_tree::MerklePath, - note::{InputNoteProvingInfo, Note, OutputNoteProvingInfo, RandomSeed}, - nullifier::{Nullifier, NullifierKeyContainer}, + note::{Note, NoteValidityPredicates, RandomSeed}, + nullifier::Nullifier, shielded_ptx::ShieldedPartialTransaction, utils::poseidon_hash, }; @@ -525,10 +520,10 @@ pub mod testing { let app_data_dynamic = poseidon_hash(app_dynamic_vp_vk[0], app_dynamic_vp_vk[1]); let rho = Nullifier::from(pallas::Base::random(&mut rng)); let value = 5000u64; - let nk = NullifierKeyContainer::random_key(&mut rng); + let nk = pallas::Base::random(&mut rng); let rseed = RandomSeed::random(&mut rng); let is_merkle_checked = true; - Note::new( + Note::new_input_note( compressed_trivial_vp_vk, app_data_static, app_data_dynamic, @@ -539,37 +534,44 @@ pub mod testing { rseed, ) }; - let output_note_1 = { + let mut output_note_1 = { let app_data_static = pallas::Base::zero(); // TODO: add real application dynamic VPs and encode them to app_data_dynamic later. // If the dynamic VP is not used, set app_data_dynamic pallas::Base::zero() by default. let app_data_dynamic = pallas::Base::zero(); - let rho = input_note_1.get_nf().unwrap(); let value = 5000u64; - let nk_com = NullifierKeyContainer::random_commitment(&mut rng); - let rseed = RandomSeed::random(&mut rng); + let nk_com = pallas::Base::random(&mut rng); let is_merkle_checked = true; - Note::new( + Note::new_output_note( compressed_trivial_vp_vk, app_data_static, app_data_dynamic, value, nk_com, - rho, is_merkle_checked, - rseed, ) }; + // Construct action pair + let merkle_path_1 = MerklePath::random(&mut rng, TAIGA_COMMITMENT_TREE_DEPTH); + let action_1 = ActionInfo::new( + input_note_1, + merkle_path_1, + None, + &mut output_note_1, + &mut rng, + ); + + // Generate notes let input_note_2 = { let app_data_static = pallas::Base::one(); let app_data_dynamic = pallas::Base::zero(); let rho = Nullifier::from(pallas::Base::random(&mut rng)); let value = 10u64; - let nk = NullifierKeyContainer::random_key(&mut rng); + let nk = pallas::Base::random(&mut rng); let rseed = RandomSeed::random(&mut rng); let is_merkle_checked = true; - Note::new( + Note::new_input_note( compressed_trivial_vp_vk, app_data_static, app_data_dynamic, @@ -580,28 +582,32 @@ pub mod testing { rseed, ) }; - let output_note_2 = { + let mut output_note_2 = { let app_data_static = pallas::Base::one(); let app_data_dynamic = pallas::Base::zero(); - let rho = input_note_2.get_nf().unwrap(); let value = 10u64; - let nk_com = NullifierKeyContainer::random_commitment(&mut rng); - let rseed = RandomSeed::random(&mut rng); + let nk_com = pallas::Base::random(&mut rng); let is_merkle_checked = true; - Note::new( + Note::new_output_note( compressed_trivial_vp_vk, app_data_static, app_data_dynamic, value, nk_com, - rho, is_merkle_checked, - rseed, ) }; - // Generate note info - let merkle_path = MerklePath::random(&mut rng, TAIGA_COMMITMENT_TREE_DEPTH); + // Construct action pair + let merkle_path_2 = MerklePath::random(&mut rng, TAIGA_COMMITMENT_TREE_DEPTH); + let action_2 = ActionInfo::new( + input_note_2, + merkle_path_2, + None, + &mut output_note_2, + &mut rng, + ); + // Create vp circuit and fill the note info let mut trivial_vp_circuit = TrivialValidityPredicateCircuit { owned_note_pub_id: input_note_1.get_nf().unwrap().inner(), @@ -612,41 +618,30 @@ pub mod testing { let trivial_app_logic_1: Box = Box::new(trivial_vp_circuit.clone()); let trivial_app_logic_2 = Box::new(trivial_vp_circuit.clone()); let trivial_dynamic_vps = vec![trivial_app_logic_1, trivial_app_logic_2]; - let input_note_proving_info_1 = InputNoteProvingInfo::new( - input_note_1, - merkle_path.clone(), - None, - input_application_vp_1, - trivial_dynamic_vps.clone(), - ); + let input_note_1_vps = + NoteValidityPredicates::new(input_application_vp_1, trivial_dynamic_vps); + // The following notes use empty logic vps and use app_data_dynamic with pallas::Base::zero() by default. trivial_vp_circuit.owned_note_pub_id = input_note_2.get_nf().unwrap().inner(); let input_application_vp_2 = Box::new(trivial_vp_circuit.clone()); - let dynamic_vps = vec![]; - let input_note_proving_info_2 = InputNoteProvingInfo::new( - input_note_2, - merkle_path, - None, - input_application_vp_2, - dynamic_vps.clone(), - ); + let input_note_2_vps = NoteValidityPredicates::new(input_application_vp_2, vec![]); 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()); + let output_note_1_vps = NoteValidityPredicates::new(output_application_vp_1, vec![]); 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); + let output_note_2_vps = NoteValidityPredicates::new(output_application_vp_2, vec![]); // Create shielded partial tx ShieldedPartialTransaction::build( - [input_note_proving_info_1, input_note_proving_info_2], - [output_note_proving_info_1, output_note_proving_info_2], + vec![action_1, action_2], + vec![input_note_1_vps, input_note_2_vps], + vec![output_note_1_vps, output_note_2_vps], vec![], &mut rng, ) + .unwrap() } } diff --git a/taiga_halo2/src/taiga_api.rs b/taiga_halo2/src/taiga_api.rs index 59d52e45..b8804e55 100644 --- a/taiga_halo2/src/taiga_api.rs +++ b/taiga_halo2/src/taiga_api.rs @@ -5,7 +5,7 @@ use crate::{ use crate::{ error::TransactionError, note::{Note, RandomSeed}, - nullifier::{Nullifier, NullifierKeyContainer}, + nullifier::Nullifier, shielded_ptx::ShieldedPartialTransaction, transaction::{ShieldedPartialTxBundle, Transaction, TransparentPartialTxBundle}, }; @@ -37,15 +37,14 @@ pub fn create_input_note( is_merkle_checked: bool, ) -> Note { let rng = OsRng; - let nk_container = NullifierKeyContainer::from_key(nk); - let rho = Nullifier::default(); + let rho = Nullifier::random(rng); let rseed = RandomSeed::random(rng); - Note::new( + Note::new_input_note( app_vk, app_data_static, app_data_dynamic, value, - nk_container, + nk, rho, is_merkle_checked, rseed, @@ -60,22 +59,15 @@ pub fn create_output_note( value: u64, // The owner of output note has the nullifer key and exposes the nullifier_key commitment to output creator. nk_com: pallas::Base, - // TODO: remove the input_nf, and get it at run time. - input_nf: Nullifier, is_merkle_checked: bool, ) -> Note { - let rng = OsRng; - let nk_container = NullifierKeyContainer::from_commitment(nk_com); - let rseed = RandomSeed::random(rng); - Note::new( + Note::new_output_note( app_vk, app_data_static, app_data_dynamic, value, - nk_container, - input_nf, + nk_com, is_merkle_checked, - rseed, ) } @@ -235,15 +227,14 @@ pub fn verify_shielded_partial_transaction(ptx_bytes: Vec) -> Result<(), Tra #[cfg(feature = "borsh")] pub mod tests { use crate::{ - note::tests::{random_input_note, random_output_note}, - taiga_api::*, + note::tests::random_note, nullifier::tests::random_nullifier_key_commitment, taiga_api::*, }; use rand::rngs::OsRng; #[test] fn note_borsh_serialization_api_test() { let mut rng = OsRng; - let input_note = random_input_note(&mut rng); + let input_note = random_note(&mut rng); { let bytes = note_serialize(&input_note).unwrap(); let de_input_note = note_deserialize(bytes).unwrap(); @@ -251,54 +242,48 @@ pub mod tests { } { - let output_note = random_output_note(&mut rng, input_note.rho); + let mut output_note = input_note; + output_note.nk_container = random_nullifier_key_commitment(&mut rng); let bytes = note_serialize(&output_note).unwrap(); let de_output_note = note_deserialize(bytes).unwrap(); assert_eq!(output_note, de_output_note); } } - #[ignore] + // #[ignore] #[test] fn ptx_example_test() { use crate::action::ActionInfo; use crate::circuit::vp_examples::TrivialValidityPredicateCircuit; use crate::constant::TAIGA_COMMITMENT_TREE_DEPTH; use crate::merkle_tree::MerklePath; - use crate::note::{ - tests::{random_input_note, random_output_note}, - RandomSeed, - }; + use crate::note::tests::random_note; let mut rng = OsRng; // construct notes - let input_note_1 = random_input_note(&mut rng); + let input_note_1 = random_note(&mut rng); let input_note_1_nf = input_note_1.get_nf().unwrap(); - let output_note_1 = random_output_note(&mut rng, input_note_1_nf); + let mut output_note_1 = random_note(&mut rng); let merkle_path_1 = MerklePath::random(&mut rng, TAIGA_COMMITMENT_TREE_DEPTH); - let anchor_1 = input_note_1.calculate_root(&merkle_path_1); - let rseed_1 = RandomSeed::random(&mut rng); let action_1 = ActionInfo::new( input_note_1, merkle_path_1, - anchor_1, - output_note_1, - rseed_1, + None, + &mut output_note_1, + &mut rng, ); - let input_note_2 = random_input_note(&mut rng); + let input_note_2 = random_note(&mut rng); let input_note_2_nf = input_note_2.get_nf().unwrap(); - let output_note_2 = random_output_note(&mut rng, input_note_2_nf); + let mut output_note_2 = random_note(&mut rng); let merkle_path_2 = MerklePath::random(&mut rng, TAIGA_COMMITMENT_TREE_DEPTH); - let anchor_2 = input_note_2.calculate_root(&merkle_path_2); - let rseed_2 = RandomSeed::random(&mut rng); let action_2 = ActionInfo::new( input_note_2, merkle_path_2, - anchor_2, - output_note_2, - rseed_2, + None, + &mut output_note_2, + &mut rng, ); // construct applications diff --git a/taiga_halo2/src/transparent_ptx.rs b/taiga_halo2/src/transparent_ptx.rs index bb05089c..026daf6e 100644 --- a/taiga_halo2/src/transparent_ptx.rs +++ b/taiga_halo2/src/transparent_ptx.rs @@ -12,14 +12,34 @@ use serde; #[cfg(feature = "borsh")] use borsh::{BorshDeserialize, BorshSerialize}; +use rand::RngCore; #[derive(Debug, Clone)] #[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct TransparentPartialTransaction { - pub inputs: Vec, - pub outputs: Vec, - pub hints: Vec, + inputs: Vec, + outputs: Vec, + hints: Vec, +} + +impl TransparentPartialTransaction { + pub fn new( + inputs: Vec, + mut outputs: Vec, + hints: Vec, + mut rng: R, + ) -> Self { + outputs + .iter_mut() + .zip(inputs.iter()) + .for_each(|(output, input)| output.note.set_rho(&input.note, &mut rng)); + Self { + inputs, + outputs, + hints, + } + } } impl Executable for TransparentPartialTransaction { @@ -102,9 +122,7 @@ pub struct OutputResource { #[cfg(test)] pub mod testing { use crate::{ - constant::TAIGA_COMMITMENT_TREE_DEPTH, - merkle_tree::MerklePath, - note::tests::{random_input_note, random_output_note}, + constant::TAIGA_COMMITMENT_TREE_DEPTH, merkle_tree::MerklePath, note::tests::random_note, transparent_ptx::*, }; use rand::rngs::OsRng; @@ -113,7 +131,7 @@ pub mod testing { pub fn create_transparent_ptx() -> TransparentPartialTransaction { let mut rng = OsRng; let input_resource_1 = { - let note = random_input_note(&mut rng); + let note = random_note(&mut rng); let merkle_path = MerklePath::random(&mut rng, TAIGA_COMMITMENT_TREE_DEPTH); InputResource { note, @@ -121,7 +139,7 @@ pub mod testing { } }; let output_resource_1 = { - let mut note = random_output_note(&mut rng, input_resource_1.note.rho); + let mut note = random_note(&mut rng); // Adjust the random note to keep the balance note.note_type = input_resource_1.note.note_type; note.value = input_resource_1.note.value; @@ -129,7 +147,7 @@ pub mod testing { }; let input_resource_2 = { - let mut note = random_input_note(&mut rng); + let mut note = random_note(&mut rng); note.is_merkle_checked = false; InputResource { note, @@ -137,17 +155,18 @@ pub mod testing { } }; let output_resource_2 = { - let mut note = random_output_note(&mut rng, input_resource_2.note.rho); + let mut note = random_note(&mut rng); // Adjust the random note to keep the balance note.note_type = input_resource_2.note.note_type; note.value = input_resource_2.note.value; OutputResource { note } }; - TransparentPartialTransaction { - inputs: vec![input_resource_1, input_resource_2], - outputs: vec![output_resource_1, output_resource_2], - hints: vec![], - } + TransparentPartialTransaction::new( + vec![input_resource_1, input_resource_2], + vec![output_resource_1, output_resource_2], + vec![], + &mut rng, + ) } }