zero-network 0.1.10

Zero network privacy-preserving blockchain
Documentation
# 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](./2_1_confidential_transfer.md) is.

The steps are following.

1. Define the `confidential_transfer` as depencencies
2. Generate test data used for `confidential_transfer`
3. Test funcitonalities

## 1. Define the confidential_transfer as depencencies
First of all, you need to define the `confidential_transfer`.

- <your-pallet>/Cargo.toml
```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.

```rust
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`.

```rust
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.

```rust
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](https://github.com/zero-network/zero/confidential_transfer.rs). Happy hacking!