Confidential Transfer Tutorial
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/KogarashiNetwork/Kogarashi", branch = "master", default-features = false }
pallet_encrypted_balance = { git = "https://github.com/KogarashiNetwork/Kogarashi", branch = "master", default-features = false }
pallet_plonk = { git = "https://github.com/KogarashiNetwork/Kogarashi", branch = "master", default-features = false }
she_elgamal = { git = "https://github.com/KogarashiNetwork/Kogarashi", branch = "master", default-features = false }
bls_12_381 = { git = "https://github.com/KogarashiNetwork/Kogarashi", 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.
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
.
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 = PlonkKey::new::<ConfidentialTransferCircuit>(&pp, label)
.expect("failed to compile circuit");
let proof = prover
.0
.create_proof(&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!