This repository has been archived by the owner on Oct 27, 2021. It is now read-only.
forked from darkrenaissance/darkfi
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstate.rs
134 lines (112 loc) · 4.16 KB
/
state.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
use std::fmt;
use bellman::groth16;
use bls12_381::Bls12;
use log::debug;
use crate::{
crypto::{coin::Coin, merkle_node::MerkleNode, note::EncryptedNote, nullifier::Nullifier},
tx,
};
pub trait ProgramState {
fn is_valid_cashier_public_key(&self, public: &jubjub::SubgroupPoint) -> bool;
fn is_valid_merkle(&self, merkle: &MerkleNode) -> bool;
fn nullifier_exists(&self, nullifier: &Nullifier) -> bool;
fn mint_pvk(&self) -> &groth16::PreparedVerifyingKey<Bls12>;
fn spend_pvk(&self) -> &groth16::PreparedVerifyingKey<Bls12>;
}
pub struct StateUpdate {
pub nullifiers: Vec<Nullifier>,
pub coins: Vec<Coin>,
pub enc_notes: Vec<EncryptedNote>,
}
pub type VerifyResult<T> = std::result::Result<T, VerifyFailed>;
#[derive(Debug)]
pub enum VerifyFailed {
InvalidCashierKey(usize),
InvalidMerkle(usize),
DuplicateNullifier(usize),
SpendProof(usize),
MintProof(usize),
ClearInputSignature(usize),
InputSignature(usize),
MissingFunds,
AssetMismatch,
}
impl std::error::Error for VerifyFailed {}
impl fmt::Display for VerifyFailed {
fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
match *self {
VerifyFailed::InvalidCashierKey(i) => {
write!(f, "Invalid cashier public key for clear input {}", i)
}
VerifyFailed::InvalidMerkle(i) => {
write!(f, "Invalid merkle root for input {}", i)
}
VerifyFailed::DuplicateNullifier(i) => {
write!(f, "Duplicate nullifier for input {}", i)
}
VerifyFailed::SpendProof(i) => write!(f, "Spend proof for input {}", i),
VerifyFailed::MintProof(i) => write!(f, "Mint proof for input {}", i),
VerifyFailed::ClearInputSignature(i) => {
write!(f, "Invalid signature for clear input {}", i)
}
VerifyFailed::InputSignature(i) => write!(f, "Invalid signature for input {}", i),
VerifyFailed::MissingFunds => {
f.write_str("Money in does not match money out (value commits)")
}
VerifyFailed::AssetMismatch => {
f.write_str("Assets don't match some inputs or outputs (token commits)")
}
}
}
}
pub fn state_transition<S: ProgramState>(
state: &async_std::sync::MutexGuard<S>,
tx: tx::Transaction,
) -> VerifyResult<StateUpdate> {
// Check deposits are legit
debug!(target: "STATE TRANSITION", "iterate clear_inputs");
for (i, input) in tx.clear_inputs.iter().enumerate() {
// Check the public key in the clear inputs
// It should be a valid public key for the cashier
if !state.is_valid_cashier_public_key(&input.signature_public) {
log::error!(target: "STATE TRANSITION", "Not valid cashier public key");
return Err(VerifyFailed::InvalidCashierKey(i));
}
}
debug!(target: "STATE TRANSITION", "iterate inputs");
for (i, input) in tx.inputs.iter().enumerate() {
// Check merkle roots
let merkle = &input.revealed.merkle_root;
// Merkle is used to know whether this is a coin that existed
// in a previous state.
if !state.is_valid_merkle(merkle) {
return Err(VerifyFailed::InvalidMerkle(i));
}
// The nullifiers should not already exist
// It is double spend protection.
let nullifier = &input.revealed.nullifier;
if state.nullifier_exists(nullifier) {
return Err(VerifyFailed::DuplicateNullifier(i));
}
}
debug!(target: "STATE TRANSITION", "Check the tx Verifies correctly");
// Check the tx verifies correctly
tx.verify(state.mint_pvk(), state.spend_pvk())?;
let mut nullifiers = vec![];
for input in tx.inputs {
nullifiers.push(input.revealed.nullifier);
}
// Newly created coins for this tx
let mut coins = vec![];
let mut enc_notes = vec![];
for output in tx.outputs {
// Gather all the coins
coins.push(Coin::new(output.revealed.coin));
enc_notes.push(output.enc_note);
}
Ok(StateUpdate {
nullifiers,
coins,
enc_notes,
})
}