bind proofs
This commit is contained in:
parent
85a3e941b9
commit
cf598f1397
|
@ -1,4 +1,4 @@
|
|||
use cl::{balance::Unit, merkle, nullifier::NullifierCommitment};
|
||||
use cl::{balance::Unit, merkle, PartialTxInputWitness};
|
||||
use once_cell::sync::Lazy;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::{Digest, Sha256};
|
||||
|
@ -62,31 +62,35 @@ impl StateWitness {
|
|||
}
|
||||
|
||||
pub fn withdraw(mut self, w: Withdraw) -> Self {
|
||||
self.included_txs.push(Tx::Withdraw(w));
|
||||
|
||||
let Withdraw {
|
||||
from,
|
||||
amount,
|
||||
to: _,
|
||||
} = w;
|
||||
bind: _,
|
||||
} = &w;
|
||||
|
||||
let from_balance = self.balances.entry(from).or_insert(0);
|
||||
let from_balance = self.balances.entry(*from).or_insert(0);
|
||||
*from_balance = from_balance
|
||||
.checked_sub(amount)
|
||||
.checked_sub(*amount)
|
||||
.expect("insufficient funds in account");
|
||||
|
||||
self.included_txs.push(Tx::Withdraw(w));
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn deposit(mut self, d: Deposit) -> Self {
|
||||
self.included_txs.push(Tx::Deposit(d));
|
||||
let Deposit {
|
||||
to,
|
||||
amount,
|
||||
bind: _,
|
||||
} = &d;
|
||||
|
||||
let Deposit { to, amount } = d;
|
||||
|
||||
let to_balance = self.balances.entry(to).or_insert(0);
|
||||
let to_balance = self.balances.entry(*to).or_insert(0);
|
||||
*to_balance += to_balance
|
||||
.checked_add(amount)
|
||||
.checked_add(*amount)
|
||||
.expect("overflow in account balance");
|
||||
|
||||
self.included_txs.push(Tx::Deposit(d));
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -144,40 +148,42 @@ impl From<StateCommitment> for [u8; 32] {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Withdraw {
|
||||
pub from: AccountId,
|
||||
pub amount: u64,
|
||||
pub to: NullifierCommitment,
|
||||
pub bind: PartialTxInputWitness,
|
||||
}
|
||||
|
||||
impl Withdraw {
|
||||
pub fn to_bytes(&self) -> [u8; 44] {
|
||||
let mut bytes = [0; 44];
|
||||
pub fn to_bytes(&self) -> [u8; 108] {
|
||||
let mut bytes = [0; 108];
|
||||
bytes[0..4].copy_from_slice(&self.from.to_le_bytes());
|
||||
bytes[4..12].copy_from_slice(&self.amount.to_le_bytes());
|
||||
bytes[12..44].copy_from_slice(self.to.as_bytes());
|
||||
bytes[12..108].copy_from_slice(&self.bind.input.commit().to_bytes());
|
||||
bytes
|
||||
}
|
||||
}
|
||||
|
||||
/// A deposit of funds into the zone
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Deposit {
|
||||
pub to: AccountId,
|
||||
pub amount: u64,
|
||||
pub bind: PartialTxInputWitness,
|
||||
}
|
||||
|
||||
impl Deposit {
|
||||
pub fn to_bytes(&self) -> [u8; 32] {
|
||||
let mut bytes = [0; 32];
|
||||
pub fn to_bytes(&self) -> [u8; 108] {
|
||||
let mut bytes = [0; 108];
|
||||
bytes[0..4].copy_from_slice(&self.to.to_le_bytes());
|
||||
bytes[4..12].copy_from_slice(&self.amount.to_le_bytes());
|
||||
bytes[12..108].copy_from_slice(&self.bind.input.commit().to_bytes());
|
||||
bytes
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum Tx {
|
||||
Withdraw(Withdraw),
|
||||
Deposit(Deposit),
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use common::{StateWitness, Tx};
|
||||
use goas_proof_statements::{zone_funds::SpendFundsPrivate, zone_state::ZoneStatePrivate};
|
||||
use std::collections::VecDeque;
|
||||
|
||||
pub fn prove_zone_stf(
|
||||
state: StateWitness,
|
||||
|
@ -8,8 +7,6 @@ pub fn prove_zone_stf(
|
|||
zone_in: cl::PartialTxInputWitness,
|
||||
zone_out: cl::PartialTxOutputWitness,
|
||||
funds_out: cl::PartialTxOutputWitness,
|
||||
withdrawals: VecDeque<cl::PartialTxOutputWitness>,
|
||||
deposits: VecDeque<cl::PartialTxInputWitness>,
|
||||
) -> ledger::DeathProof {
|
||||
let private_inputs = ZoneStatePrivate {
|
||||
state,
|
||||
|
@ -17,8 +14,6 @@ pub fn prove_zone_stf(
|
|||
zone_in,
|
||||
zone_out,
|
||||
funds_out,
|
||||
withdrawals,
|
||||
deposits,
|
||||
};
|
||||
|
||||
let env = risc0_zkvm::ExecutorEnv::builder()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::collections::{BTreeMap, VecDeque};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use cl::{NoteWitness, NullifierNonce, NullifierSecret};
|
||||
use common::{StateWitness, Tx, ZoneMetadata, ZONE_CL_FUNDS_UNIT};
|
||||
|
@ -65,13 +65,28 @@ fn test_withdrawal() {
|
|||
cl::InputWitness::public(zone_fund_utxo(100, init_state.zone_metadata, &mut rng));
|
||||
let zone_state_in = cl::InputWitness::public(zone_state_utxo(&init_state, &mut rng));
|
||||
|
||||
let alice_intent = cl::InputWitness::random(
|
||||
cl::OutputWitness::random(
|
||||
NoteWitness::stateless(1, *ZONE_CL_FUNDS_UNIT, DeathProof::nop_constraint()), // TODO, intent should be in the death constraint
|
||||
alice_sk.commit(),
|
||||
&mut rng,
|
||||
),
|
||||
alice_sk,
|
||||
&mut rng,
|
||||
);
|
||||
|
||||
let mut withdraw_ptx = cl::PartialTxWitness {
|
||||
inputs: vec![zone_state_in, zone_fund_in, alice_intent],
|
||||
outputs: vec![],
|
||||
};
|
||||
|
||||
let withdraw = common::Withdraw {
|
||||
from: alice,
|
||||
amount: 78,
|
||||
to: alice_sk.commit(),
|
||||
bind: withdraw_ptx.input_witness(2),
|
||||
};
|
||||
|
||||
let end_state = init_state.clone().withdraw(withdraw).evolve_nonce();
|
||||
let end_state = init_state.clone().withdraw(withdraw.clone()).evolve_nonce();
|
||||
|
||||
let zone_state_out = cl::OutputWitness::public(
|
||||
cl::NoteWitness {
|
||||
|
@ -98,22 +113,17 @@ fn test_withdrawal() {
|
|||
&mut rng,
|
||||
);
|
||||
|
||||
let withdraw_ptx = cl::PartialTxWitness {
|
||||
inputs: vec![zone_state_in, zone_fund_in],
|
||||
outputs: vec![zone_state_out, zone_fund_out, alice_withdrawal],
|
||||
};
|
||||
withdraw_ptx.outputs = vec![zone_state_out, zone_fund_out, alice_withdrawal];
|
||||
|
||||
let death_proofs = BTreeMap::from_iter([
|
||||
(
|
||||
zone_state_in.nullifier(),
|
||||
executor::prove_zone_stf(
|
||||
init_state.clone(),
|
||||
vec![Tx::Withdraw(withdraw)],
|
||||
vec![Tx::Withdraw(withdraw.clone())],
|
||||
withdraw_ptx.input_witness(0), // input state note (input #0)
|
||||
withdraw_ptx.output_witness(0), // output state note (output #0)
|
||||
withdraw_ptx.output_witness(1), // output funds note (output #1)
|
||||
VecDeque::from_iter([withdraw_ptx.output_witness(2)]), // alice withdrawal
|
||||
VecDeque::new(), // no deposits
|
||||
),
|
||||
),
|
||||
(
|
||||
|
@ -124,11 +134,18 @@ fn test_withdrawal() {
|
|||
&end_state,
|
||||
),
|
||||
),
|
||||
(
|
||||
alice_intent.nullifier(),
|
||||
DeathProof::prove_nop(alice_intent.nullifier(), withdraw_ptx.commit().root()),
|
||||
),
|
||||
]);
|
||||
|
||||
println!("done");
|
||||
|
||||
let note_commitments = vec![
|
||||
zone_state_in.note_commitment(),
|
||||
zone_fund_in.note_commitment(),
|
||||
alice_intent.note_commitment(),
|
||||
];
|
||||
|
||||
let withdraw_proof =
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use common::{StateWitness, Tx};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::VecDeque;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct ZoneStatePrivate {
|
||||
|
@ -13,8 +12,4 @@ pub struct ZoneStatePrivate {
|
|||
/// This means that while there's nothing to prevent creation of notes with the same characteristics of zone
|
||||
/// funds, those would not be tracked by the zone state and can be ignored.
|
||||
pub funds_out: cl::PartialTxOutputWitness,
|
||||
/// Each note is the result of the execution of a withdrawal request
|
||||
pub withdrawals: VecDeque<cl::PartialTxOutputWitness>,
|
||||
/// Each note is providing funds for a deposit request
|
||||
pub deposits: VecDeque<cl::PartialTxInputWitness>,
|
||||
}
|
||||
|
|
|
@ -1,58 +1,18 @@
|
|||
use cl::{
|
||||
note::NoteWitness,
|
||||
nullifier::NullifierNonce,
|
||||
output::OutputWitness,
|
||||
partial_tx::{PartialTxInputWitness, PartialTxOutputWitness},
|
||||
PtxRoot,
|
||||
};
|
||||
use cl::{note::NoteWitness, nullifier::NullifierNonce, output::OutputWitness, PtxRoot};
|
||||
|
||||
use common::*;
|
||||
use goas_proof_statements::zone_state::ZoneStatePrivate;
|
||||
use ledger_proof_statements::death_constraint::DeathConstraintPublic;
|
||||
use risc0_zkvm::guest::env;
|
||||
|
||||
fn withdraw(
|
||||
state: StateWitness,
|
||||
output_root: [u8; 32],
|
||||
withdrawal_req: Withdraw,
|
||||
withdrawal: PartialTxOutputWitness,
|
||||
) -> StateWitness {
|
||||
// 1) check the correct amount of funds is being spent
|
||||
assert_eq!(withdrawal.output.note.value, withdrawal_req.amount);
|
||||
assert_eq!(withdrawal.output.note.unit, *ZONE_CL_FUNDS_UNIT);
|
||||
// 2) check the correct recipient is being paid
|
||||
assert_eq!(withdrawal.output.nf_pk, withdrawal_req.to);
|
||||
|
||||
assert_eq!(output_root, withdrawal.output_root());
|
||||
|
||||
state.withdraw(withdrawal_req)
|
||||
fn withdraw(state: StateWitness, input_root: [u8; 32], withdrawal: Withdraw) -> StateWitness {
|
||||
assert_eq!(input_root, withdrawal.bind.input_root());
|
||||
state.withdraw(withdrawal)
|
||||
}
|
||||
|
||||
fn deposit(
|
||||
state: StateWitness,
|
||||
input_root: [u8; 32],
|
||||
deposit_req: Deposit,
|
||||
deposit: PartialTxInputWitness,
|
||||
) -> StateWitness {
|
||||
assert_eq!(deposit.input_root(), input_root);
|
||||
|
||||
// 1) Check the deposit note is not already under control of the zone
|
||||
assert_ne!(
|
||||
deposit.input.note.death_constraint,
|
||||
state.zone_metadata.funds_vk
|
||||
);
|
||||
|
||||
// 2) Check the deposit note is for the correct amount
|
||||
assert_eq!(deposit.input.note.unit, *ZONE_CL_FUNDS_UNIT);
|
||||
assert_eq!(deposit.input.note.value, deposit_req.amount);
|
||||
|
||||
// 3) Check the deposit note is for the correct recipient
|
||||
assert_eq!(
|
||||
AccountId::from_le_bytes(<[u8; 4]>::try_from(&deposit.input.note.state[..4]).unwrap()),
|
||||
deposit_req.to
|
||||
);
|
||||
|
||||
state.deposit(deposit_req)
|
||||
fn deposit(state: StateWitness, input_root: [u8; 32], deposit: Deposit) -> StateWitness {
|
||||
assert_eq!(deposit.bind.input_root(), input_root);
|
||||
state.deposit(deposit)
|
||||
}
|
||||
|
||||
fn validate_zone_transition(
|
||||
|
@ -113,8 +73,6 @@ fn main() {
|
|||
zone_in,
|
||||
zone_out,
|
||||
funds_out,
|
||||
mut withdrawals,
|
||||
mut deposits,
|
||||
} = env::read();
|
||||
|
||||
let input_root = zone_in.input_root();
|
||||
|
@ -129,8 +87,8 @@ fn main() {
|
|||
|
||||
for input in inputs {
|
||||
state = match input {
|
||||
Tx::Withdraw(w) => withdraw(state, output_root, w, withdrawals.pop_front().unwrap()),
|
||||
Tx::Deposit(d) => deposit(state, input_root, d, deposits.pop_front().unwrap()),
|
||||
Tx::Withdraw(w) => withdraw(state, input_root, w),
|
||||
Tx::Deposit(d) => deposit(state, input_root, d),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue