confidential_transfer
In this tutorial, we are going to generate test data and test its functionalities. We assume that you already unserstand what Confidential Transfer is.
The steps are following.
- Define the
confidential_transfer
as depencencies - Generate test data used for
confidential_transfer
- Test funcitonalities
1. Define the confidential_transfer as depencencies
First of all, you need to define the confidential_transfer
.
/Cargo.toml
confidential_transfer = { git = "https://github.com/zero-network/zero", branch = "master", default-features = false }
pallet_encrypted_balance = { git = "https://github.com/zero-network/zero", branch = "master", default-features = false }
pallet_plonk = { git = "https://github.com/zero-network/zero", branch = "master", default-features = false }
zero_elgamal = { git = "https://github.com/zero-network/zero", branch = "master", default-features = false }
zero_bls12_381 = { git = "https://github.com/zero-network/zero", branch = "master", default-features = false }
rand_core = {version="0.6", default-features = false }
The confidential_transfer
depends on rand_core
so please import it.
2. Generate test data used for confidential_transfer
Secondly, we would like like to setup the Alice and Bob account on testing runtime. Define the new_test_ext
for genesis config and reflect the testing data for runtime storage.
#![allow(unused)] fn main() { fn new_test_ext( alice_address: u64, alice_private_key: Fp, alice_balance: u32, alice_radomness: Fp, bob_private_key: Fp, bob_address: u64, bob_balance: u32, bob_radomness: Fp, ) -> sp_io::TestExternalities { let alice_balance = EncryptedNumber::encrypt(alice_private_key, alice_balance, alice_radomness); let bob_balance = EncryptedNumber::encrypt(bob_private_key, bob_balance, bob_radomness); let mut t = frame_system::GenesisConfig::default() .build_storage::<TestRuntime>() .unwrap(); pallet_encrypted_balance::GenesisConfig::<TestRuntime> { balances: vec![(alice_address, alice_balance), (bob_address, bob_balance)], } .assimilate_storage(&mut t) .unwrap(); let mut ext = sp_io::TestExternalities::new(t); ext.execute_with(|| System::set_block_number(1)); ext } }
Thirdly, we define generate_default_test_data
to generate parameters used for confidential_transfer
.
#![allow(unused)] fn main() { fn generate_default_test_data() -> (u64, Fp, u16, Fp, Fp, u64, u16, Fp, u16, u16, u16) { let mut rng = rand::thread_rng(); let alice_address = rng.gen::<u64>(); let alice_private_key = Fp::random(OsRng); let alice_balance = rng.gen::<u16>(); let alice_radomness = Fp::random(OsRng); let bob_private_key = Fp::random(OsRng); let bob_address = rng.gen::<u64>(); let bob_balance = rng.gen::<u16>(); let bob_radomness = Fp::random(OsRng); let transfer_amount = rng.gen_range(0..alice_balance); let alice_after_balance = alice_balance - transfer_amount; let bob_after_balance = bob_balance + transfer_amount; ( alice_address, alice_private_key, alice_balance, alice_radomness, bob_private_key, bob_address, bob_balance, bob_radomness, transfer_amount, alice_after_balance, bob_after_balance, ) } }
3. Test funcitonalities
Finally, we combine previous sections together and test functionalities.
fn main() { let k = 14; let label = b"verify"; let mut rng = get_rng(); let ( alice_address, alice_private_key, alice_balance, alice_radomness, bob_private_key, bob_address, bob_balance, bob_radomness, transfer_amount, alice_after_balance, bob_after_balance, transfer_randomness, ) = generate_default_test_data(); new_test_ext( alice_address, alice_private_key, alice_balance, alice_radomness, bob_private_key, bob_address, bob_balance, bob_radomness, ) .execute_with(|| { // default balance decryption check let alice_encrypted_balance = ConfidentialTransfer::total_balance(&alice_address); let alice_raw_balance = alice_encrypted_balance.decrypt(alice_private_key); let bob_encrypted_balance = ConfidentialTransfer::total_balance(&bob_address); let bob_raw_balance = bob_encrypted_balance.decrypt(bob_private_key); assert_eq!(alice_raw_balance.unwrap() as u16, alice_balance); assert_eq!(bob_raw_balance.unwrap() as u16, bob_balance); // trusted setup check let result = ConfidentialTransfer::trusted_setup(Origin::signed(alice_address), k, rng.clone()); assert_ok!(result); // proof generation let pp = Plonk::public_parameter().unwrap(); let alice_public_key = GENERATOR_EXTENDED * alice_private_key; let bob_public_key = GENERATOR_EXTENDED * bob_private_key; let transfer_amount_scalar = Fp::from(transfer_amount as u64); let alice_after_balance_scalar = Fp::from(alice_after_balance as u64); let alice_balance = EncryptedNumber::encrypt(alice_private_key, alice_balance.into(), alice_radomness); let alice_transfer_amount = EncryptedNumber::encrypt( alice_private_key, transfer_amount.into(), transfer_randomness, ); let bob_encrypted_transfer_amount = (GENERATOR_EXTENDED * transfer_amount_scalar) + (bob_public_key * transfer_randomness); let alice_public_key = JubJubAffine::from(alice_public_key); let bob_public_key = JubJubAffine::from(bob_public_key); let bob_encrypted_transfer_amount = JubJubAffine::from(bob_encrypted_transfer_amount); let bob_encrypted_transfer_amount_other = (GENERATOR_EXTENDED * transfer_randomness).into(); let confidential_transfer_circuit = ConfidentialTransferCircuit::new( alice_public_key, bob_public_key, alice_balance, alice_transfer_amount, bob_encrypted_transfer_amount, alice_private_key, transfer_amount_scalar, alice_after_balance_scalar, transfer_randomness, ); let prover = Compiler::compile::<ConfidentialTransferCircuit>(&pp, label) .expect("failed to compile circuit"); let proof = prover .0 .prove(&mut rng, &confidential_transfer_circuit) .expect("failed to prove"); // confidential transfer check let transaction_params = ConfidentialTransferTransaction::new( alice_public_key, bob_public_key, alice_transfer_amount, bob_encrypted_transfer_amount, bob_encrypted_transfer_amount_other, ); let result = ConfidentialTransfer::confidential_transfer( Origin::signed(alice_address), bob_address, proof.0, transaction_params, ); assert_ok!(result); // balance transition check let alice_balance = ConfidentialTransfer::total_balance(&alice_address); let alice_raw_balance = alice_balance.decrypt(alice_private_key); let bob_balance = ConfidentialTransfer::total_balance(&bob_address); let bob_raw_balance = bob_balance.decrypt(bob_private_key); assert_eq!(alice_raw_balance.unwrap() as u16, alice_after_balance); assert_eq!(bob_raw_balance.unwrap() as u16, bob_after_balance); }) }
With above tests, we can confirm that confidential transfer works correctly. You can check the confidential_transfer
example here. Happy hacking!