101 lines
3.6 KiB
Rust
Raw Normal View History

2025-07-11 19:21:06 -03:00
use transfer_methods::{
TRANSFER_ELF, TRANSFER_ID
};
use outer_methods::{
OUTER_ELF, OUTER_ID
};
use risc0_zkvm::{default_prover, ExecutorEnv, Receipt};
2025-07-14 16:47:43 -03:00
use toy_example_core::account::Account;
2025-07-11 19:21:06 -03:00
2025-07-11 19:35:54 -03:00
/// A private execution of the transfer function.
/// This actually "burns" a sender private account and "mints" two new private accounts:
2025-07-11 19:44:43 -03:00
/// one for the recipient with the transferred balance, and another owned by the sender with the remaining balance.
2025-07-11 19:21:06 -03:00
fn run_private_execution_of_transfer_program() {
let commitment_tree_root = [0xdd, 0xee, 0xaa, 0xdd, 0xbb, 0xee, 0xee, 0xff];
2025-07-11 19:35:54 -03:00
// This is supposed to be an existing private account (UTXO) with balance equal to 150.
// And it is supposed to be a private account of the user running this private execution (hence the access to the private key)
2025-07-11 19:21:06 -03:00
let sender_private_key = [0; 8];
2025-07-11 19:44:43 -03:00
let sender = {
// Creating it now but it's supposed to be already created by other previous transactions.
let mut account = Account::new_from_private_key(sender_private_key, [1; 8]);
account.balance = 150;
account
};
2025-07-11 19:21:06 -03:00
let balance_to_move: u128 = 3;
2025-07-11 19:35:54 -03:00
// This is the new private account (UTXO) being minted by this private execution.
// (The `receiver_address` would be <Npk> in UTXO's terminology)
let receiver_address = [99; 8];
let receiver = Account::new(receiver_address, [1; 8]);
// Prove inner program and get post state of the accounts
2025-07-11 19:21:06 -03:00
let (inner_receipt, sender_post, receiver_post) = prove_inner(sender.clone(), receiver.clone(), balance_to_move);
2025-07-11 19:35:54 -03:00
// Prove outer program.
// This computes the nullifier for the input account
// and commitments for the accounts post states.
2025-07-11 19:21:06 -03:00
let mut env_builder = ExecutorEnv::builder();
env_builder.add_assumption(inner_receipt);
env_builder.write(&sender_private_key).unwrap();
env_builder.write(&sender).unwrap();
env_builder.write(&receiver) .unwrap();
env_builder.write(&sender_post).unwrap();
env_builder.write(&receiver_post).unwrap();
env_builder.write(&commitment_tree_root).unwrap();
env_builder.write(&TRANSFER_ID).unwrap();
let env = env_builder.build().unwrap();
let prover = default_prover();
let prove_info = prover
.prove(env, OUTER_ELF)
.unwrap();
let receipt = prove_info.receipt;
// Sanity check
receipt.verify(OUTER_ID).unwrap();
let output: [[u32; 8]; 3] = receipt.journal.decode().unwrap();
println!("nullifier: {:?}", output[0]);
println!("commitment_1: {:?}", output[1]);
println!("commitment_2: {:?}", output[2]);
}
2025-07-11 19:35:54 -03:00
fn prove_inner(sender: Account, receiver: Account, balance_to_move: u128) -> (Receipt, Account, Account) {
let mut env_builder = ExecutorEnv::builder();
env_builder.write(&sender).unwrap();
env_builder.write(&receiver).unwrap();
env_builder.write(&balance_to_move).unwrap();
let env = env_builder.build().unwrap();
let prover = default_prover();
let prove_info = prover
.prove(env, TRANSFER_ELF)
.unwrap();
let receipt = prove_info.receipt;
let output: [Account; 4] = receipt.journal.decode().unwrap();
let [_, _, sender_post, receiver_post] = output;
println!("sender_before: {:?}, sender_after: {:?}", sender, sender_post);
println!("receiver_before: {:?}, receiver_after: {:?}", receiver, receiver_post);
// Sanity check
receipt
.verify(TRANSFER_ID)
.unwrap();
(receipt, sender_post, receiver_post)
}
2025-07-11 19:21:06 -03:00
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_private() {
run_private_execution_of_transfer_program();
}
2025-07-14 16:47:43 -03:00
}