mirror of
https://github.com/logos-blockchain/logos-execution-zone.git
synced 2026-05-20 23:19:49 +00:00
add root history
This commit is contained in:
parent
9ff6a5bc85
commit
20897596b0
@ -38,11 +38,10 @@ pub mod error;
|
|||||||
|
|
||||||
pub type CommitmentSetDigest = [u8; 32];
|
pub type CommitmentSetDigest = [u8; 32];
|
||||||
pub type MembershipProof = (usize, Vec<[u8; 32]>);
|
pub type MembershipProof = (usize, Vec<[u8; 32]>);
|
||||||
pub fn verify_membership_proof(
|
pub fn compute_root_associated_to_path(
|
||||||
commitment: &Commitment,
|
commitment: &Commitment,
|
||||||
proof: &MembershipProof,
|
proof: &MembershipProof,
|
||||||
digest: &CommitmentSetDigest,
|
) -> CommitmentSetDigest {
|
||||||
) -> bool {
|
|
||||||
let value_bytes = commitment.to_byte_array();
|
let value_bytes = commitment.to_byte_array();
|
||||||
let mut result: [u8; 32] = Impl::hash_bytes(&value_bytes)
|
let mut result: [u8; 32] = Impl::hash_bytes(&value_bytes)
|
||||||
.as_bytes()
|
.as_bytes()
|
||||||
@ -64,7 +63,7 @@ pub fn verify_membership_proof(
|
|||||||
}
|
}
|
||||||
level_index >>= 1;
|
level_index >>= 1;
|
||||||
}
|
}
|
||||||
&result == digest
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type EphemeralPublicKey = Secp256k1Point;
|
pub type EphemeralPublicKey = Secp256k1Point;
|
||||||
@ -243,7 +242,6 @@ pub struct PrivacyPreservingCircuitInput {
|
|||||||
)>,
|
)>,
|
||||||
pub private_account_auth: Vec<(NullifierSecretKey, MembershipProof)>,
|
pub private_account_auth: Vec<(NullifierSecretKey, MembershipProof)>,
|
||||||
pub program_id: ProgramId,
|
pub program_id: ProgramId,
|
||||||
pub commitment_set_digest: CommitmentSetDigest,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
@ -253,8 +251,7 @@ pub struct PrivacyPreservingCircuitOutput {
|
|||||||
pub public_post_states: Vec<Account>,
|
pub public_post_states: Vec<Account>,
|
||||||
pub encrypted_private_post_states: Vec<EncryptedAccountData>,
|
pub encrypted_private_post_states: Vec<EncryptedAccountData>,
|
||||||
pub new_commitments: Vec<Commitment>,
|
pub new_commitments: Vec<Commitment>,
|
||||||
pub new_nullifiers: Vec<Nullifier>,
|
pub new_nullifiers: Vec<(Nullifier, CommitmentSetDigest)>,
|
||||||
pub commitment_set_digest: CommitmentSetDigest,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "host")]
|
#[cfg(feature = "host")]
|
||||||
@ -313,11 +310,13 @@ mod tests {
|
|||||||
&NullifierPublicKey::from(&[1; 32]),
|
&NullifierPublicKey::from(&[1; 32]),
|
||||||
&Account::default(),
|
&Account::default(),
|
||||||
)],
|
)],
|
||||||
new_nullifiers: vec![Nullifier::new(
|
new_nullifiers: vec![(
|
||||||
&Commitment::new(&NullifierPublicKey::from(&[2; 32]), &Account::default()),
|
Nullifier::new(
|
||||||
&[1; 32],
|
&Commitment::new(&NullifierPublicKey::from(&[2; 32]), &Account::default()),
|
||||||
|
&[1; 32],
|
||||||
|
),
|
||||||
|
[0xab; 32],
|
||||||
)],
|
)],
|
||||||
commitment_set_digest: [0xab; 32],
|
|
||||||
};
|
};
|
||||||
let bytes = output.to_bytes();
|
let bytes = output.to_bytes();
|
||||||
let output_from_slice: PrivacyPreservingCircuitOutput = from_slice(&bytes).unwrap();
|
let output_from_slice: PrivacyPreservingCircuitOutput = from_slice(&bytes).unwrap();
|
||||||
|
|||||||
@ -2,8 +2,9 @@ use risc0_zkvm::{guest::env, serde::to_vec};
|
|||||||
|
|
||||||
use nssa_core::{
|
use nssa_core::{
|
||||||
account::{Account, AccountWithMetadata, Commitment, Nullifier, NullifierPublicKey},
|
account::{Account, AccountWithMetadata, Commitment, Nullifier, NullifierPublicKey},
|
||||||
|
compute_root_associated_to_path,
|
||||||
program::{validate_execution, ProgramOutput, DEFAULT_PROGRAM_ID},
|
program::{validate_execution, ProgramOutput, DEFAULT_PROGRAM_ID},
|
||||||
verify_membership_proof, EncryptedAccountData, EphemeralPublicKey, EphemeralSecretKey,
|
CommitmentSetDigest, EncryptedAccountData, EphemeralPublicKey, EphemeralSecretKey,
|
||||||
IncomingViewingPublicKey, PrivacyPreservingCircuitInput, PrivacyPreservingCircuitOutput,
|
IncomingViewingPublicKey, PrivacyPreservingCircuitInput, PrivacyPreservingCircuitOutput,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -15,7 +16,6 @@ fn main() {
|
|||||||
private_account_keys,
|
private_account_keys,
|
||||||
private_account_auth,
|
private_account_auth,
|
||||||
program_id,
|
program_id,
|
||||||
commitment_set_digest,
|
|
||||||
} = env::read();
|
} = env::read();
|
||||||
|
|
||||||
// TODO: Check that `program_execution_proof` is one of the allowed built-in programs
|
// TODO: Check that `program_execution_proof` is one of the allowed built-in programs
|
||||||
@ -44,7 +44,7 @@ fn main() {
|
|||||||
let mut public_post_states: Vec<Account> = Vec::new();
|
let mut public_post_states: Vec<Account> = Vec::new();
|
||||||
let mut encrypted_private_post_states: Vec<EncryptedAccountData> = Vec::new();
|
let mut encrypted_private_post_states: Vec<EncryptedAccountData> = Vec::new();
|
||||||
let mut new_commitments: Vec<Commitment> = Vec::new();
|
let mut new_commitments: Vec<Commitment> = Vec::new();
|
||||||
let mut new_nullifiers: Vec<Nullifier> = Vec::new();
|
let mut new_nullifiers: Vec<(Nullifier, CommitmentSetDigest)> = Vec::new();
|
||||||
|
|
||||||
let mut private_nonces_iter = private_account_nonces.iter();
|
let mut private_nonces_iter = private_account_nonces.iter();
|
||||||
let mut private_keys_iter = private_account_keys.iter();
|
let mut private_keys_iter = private_account_keys.iter();
|
||||||
@ -80,15 +80,10 @@ fn main() {
|
|||||||
panic!("Npk mismatch");
|
panic!("Npk mismatch");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify pre-state commitment membership
|
// Compute commitment set digest associated with provided auth path
|
||||||
let commitment_pre = Commitment::new(Npk, &pre_states[i].account);
|
let commitment_pre = Commitment::new(Npk, &pre_states[i].account);
|
||||||
if !verify_membership_proof(
|
let set_digest =
|
||||||
&commitment_pre,
|
compute_root_associated_to_path(&commitment_pre, membership_proof);
|
||||||
membership_proof,
|
|
||||||
&commitment_set_digest,
|
|
||||||
) {
|
|
||||||
panic!("Membership proof invalid");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check pre_state authorization
|
// Check pre_state authorization
|
||||||
if !pre_states[i].is_authorized {
|
if !pre_states[i].is_authorized {
|
||||||
@ -97,7 +92,7 @@ fn main() {
|
|||||||
|
|
||||||
// Compute nullifier
|
// Compute nullifier
|
||||||
let nullifier = Nullifier::new(&commitment_pre, nsk);
|
let nullifier = Nullifier::new(&commitment_pre, nsk);
|
||||||
new_nullifiers.push(nullifier);
|
new_nullifiers.push((nullifier, set_digest));
|
||||||
} else {
|
} else {
|
||||||
if pre_states[i].account != Account::default() {
|
if pre_states[i].account != Account::default() {
|
||||||
panic!("Found new private account with non default values.");
|
panic!("Found new private account with non default values.");
|
||||||
@ -156,7 +151,6 @@ fn main() {
|
|||||||
encrypted_private_post_states,
|
encrypted_private_post_states,
|
||||||
new_commitments,
|
new_commitments,
|
||||||
new_nullifiers,
|
new_nullifiers,
|
||||||
commitment_set_digest,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
env::commit(&output);
|
env::commit(&output);
|
||||||
|
|||||||
@ -173,7 +173,7 @@ fn verify_authentication_path(value: &Value, index: usize, path: &[Node], root:
|
|||||||
|
|
||||||
fn prev_power_of_two(x: usize) -> usize {
|
fn prev_power_of_two(x: usize) -> usize {
|
||||||
if x == 0 {
|
if x == 0 {
|
||||||
return 0; // define as 0
|
return 0;
|
||||||
}
|
}
|
||||||
1 << (usize::BITS as usize - x.leading_zeros() as usize - 1)
|
1 << (usize::BITS as usize - x.leading_zeros() as usize - 1)
|
||||||
}
|
}
|
||||||
@ -314,10 +314,10 @@ mod tests {
|
|||||||
let expected_root =
|
let expected_root =
|
||||||
hex!("48c73f7821a58a8d2a703e5b39c571c0aa20cf14abcd0af8f2b955bc202998de");
|
hex!("48c73f7821a58a8d2a703e5b39c571c0aa20cf14abcd0af8f2b955bc202998de");
|
||||||
|
|
||||||
tree.insert(values[0]);
|
assert_eq!(0, tree.insert(values[0]));
|
||||||
tree.insert(values[1]);
|
assert_eq!(1, tree.insert(values[1]));
|
||||||
tree.insert(values[2]);
|
assert_eq!(2, tree.insert(values[2]));
|
||||||
tree.insert(values[3]);
|
assert_eq!(3, tree.insert(values[3]));
|
||||||
|
|
||||||
assert_eq!(tree.root(), expected_root);
|
assert_eq!(tree.root(), expected_root);
|
||||||
}
|
}
|
||||||
@ -331,9 +331,9 @@ mod tests {
|
|||||||
let expected_root =
|
let expected_root =
|
||||||
hex!("c8d3d8d2b13f27ceeccdc699119871f9f32ea7ed86ff45d0ad11f77b28cd7568");
|
hex!("c8d3d8d2b13f27ceeccdc699119871f9f32ea7ed86ff45d0ad11f77b28cd7568");
|
||||||
|
|
||||||
tree.insert(values[0]);
|
assert_eq!(0, tree.insert(values[0]));
|
||||||
tree.insert(values[1]);
|
assert_eq!(1, tree.insert(values[1]));
|
||||||
tree.insert(values[2]);
|
assert_eq!(2, tree.insert(values[2]));
|
||||||
|
|
||||||
assert_eq!(tree.root(), expected_root);
|
assert_eq!(tree.root(), expected_root);
|
||||||
}
|
}
|
||||||
@ -347,9 +347,9 @@ mod tests {
|
|||||||
let expected_root =
|
let expected_root =
|
||||||
hex!("c8d3d8d2b13f27ceeccdc699119871f9f32ea7ed86ff45d0ad11f77b28cd7568");
|
hex!("c8d3d8d2b13f27ceeccdc699119871f9f32ea7ed86ff45d0ad11f77b28cd7568");
|
||||||
|
|
||||||
tree.insert(values[0]);
|
assert_eq!(0, tree.insert(values[0]));
|
||||||
tree.insert(values[1]);
|
assert_eq!(1, tree.insert(values[1]));
|
||||||
tree.insert(values[2]);
|
assert_eq!(2, tree.insert(values[2]));
|
||||||
|
|
||||||
assert_eq!(tree.root(), expected_root);
|
assert_eq!(tree.root(), expected_root);
|
||||||
}
|
}
|
||||||
@ -361,9 +361,9 @@ mod tests {
|
|||||||
let values = [[1; 32], [2; 32], [3; 32]];
|
let values = [[1; 32], [2; 32], [3; 32]];
|
||||||
let expected_tree = MerkleTree::new(&values);
|
let expected_tree = MerkleTree::new(&values);
|
||||||
|
|
||||||
tree.insert(values[0]);
|
assert_eq!(0, tree.insert(values[0]));
|
||||||
tree.insert(values[1]);
|
assert_eq!(1, tree.insert(values[1]));
|
||||||
tree.insert(values[2]);
|
assert_eq!(2, tree.insert(values[2]));
|
||||||
|
|
||||||
assert_eq!(expected_tree, tree);
|
assert_eq!(expected_tree, tree);
|
||||||
}
|
}
|
||||||
@ -375,10 +375,10 @@ mod tests {
|
|||||||
let values = [[1; 32], [2; 32], [3; 32], [4; 32]];
|
let values = [[1; 32], [2; 32], [3; 32], [4; 32]];
|
||||||
let expected_tree = MerkleTree::new(&values);
|
let expected_tree = MerkleTree::new(&values);
|
||||||
|
|
||||||
tree.insert(values[0]);
|
assert_eq!(0, tree.insert(values[0]));
|
||||||
tree.insert(values[1]);
|
assert_eq!(1, tree.insert(values[1]));
|
||||||
tree.insert(values[2]);
|
assert_eq!(2, tree.insert(values[2]));
|
||||||
tree.insert(values[3]);
|
assert_eq!(3, tree.insert(values[3]));
|
||||||
|
|
||||||
assert_eq!(expected_tree, tree);
|
assert_eq!(expected_tree, tree);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,7 +33,6 @@ pub fn execute_and_prove(
|
|||||||
)],
|
)],
|
||||||
private_account_auth: &[(NullifierSecretKey, MembershipProof)],
|
private_account_auth: &[(NullifierSecretKey, MembershipProof)],
|
||||||
program: &Program,
|
program: &Program,
|
||||||
commitment_set_digest: &CommitmentSetDigest,
|
|
||||||
) -> Result<(PrivacyPreservingCircuitOutput, Proof), NssaError> {
|
) -> Result<(PrivacyPreservingCircuitOutput, Proof), NssaError> {
|
||||||
let inner_receipt = execute_and_prove_program(program, pre_states, instruction_data)?;
|
let inner_receipt = execute_and_prove_program(program, pre_states, instruction_data)?;
|
||||||
|
|
||||||
@ -49,7 +48,6 @@ pub fn execute_and_prove(
|
|||||||
private_account_keys: private_account_keys.to_vec(),
|
private_account_keys: private_account_keys.to_vec(),
|
||||||
private_account_auth: private_account_auth.to_vec(),
|
private_account_auth: private_account_auth.to_vec(),
|
||||||
program_id: program.id(),
|
program_id: program.id(),
|
||||||
commitment_set_digest: *commitment_set_digest,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Prove circuit.
|
// Prove circuit.
|
||||||
@ -157,7 +155,6 @@ mod tests {
|
|||||||
&[(recipient_keys.npk(), recipient_keys.ivk(), [3; 32])],
|
&[(recipient_keys.npk(), recipient_keys.ivk(), [3; 32])],
|
||||||
&[],
|
&[],
|
||||||
&Program::authenticated_transfer_program(),
|
&Program::authenticated_transfer_program(),
|
||||||
&[99; 32],
|
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -169,7 +166,6 @@ mod tests {
|
|||||||
assert_eq!(sender_post, expected_sender_post);
|
assert_eq!(sender_post, expected_sender_post);
|
||||||
assert_eq!(output.new_commitments.len(), 1);
|
assert_eq!(output.new_commitments.len(), 1);
|
||||||
assert_eq!(output.new_nullifiers.len(), 0);
|
assert_eq!(output.new_nullifiers.len(), 0);
|
||||||
assert_eq!(output.commitment_set_digest, [99; 32]);
|
|
||||||
assert_eq!(output.encrypted_private_post_states.len(), 1);
|
assert_eq!(output.encrypted_private_post_states.len(), 1);
|
||||||
|
|
||||||
let recipient_post = output.encrypted_private_post_states[0]
|
let recipient_post = output.encrypted_private_post_states[0]
|
||||||
@ -199,7 +195,13 @@ mod tests {
|
|||||||
};
|
};
|
||||||
let balance_to_move: u128 = 37;
|
let balance_to_move: u128 = 37;
|
||||||
|
|
||||||
let expected_new_nullifiers = vec![Nullifier::new(&commitment_sender, &sender_keys.nsk)];
|
let mut commitment_set = CommitmentSet::with_capacity(2);
|
||||||
|
commitment_set.extend(&[commitment_sender.clone()]);
|
||||||
|
|
||||||
|
let expected_new_nullifiers = vec![(
|
||||||
|
Nullifier::new(&commitment_sender, &sender_keys.nsk),
|
||||||
|
commitment_set.digest(),
|
||||||
|
)];
|
||||||
|
|
||||||
let program = Program::authenticated_transfer_program();
|
let program = Program::authenticated_transfer_program();
|
||||||
|
|
||||||
@ -220,9 +222,6 @@ mod tests {
|
|||||||
Commitment::new(&recipient_keys.npk(), &expected_private_account_2),
|
Commitment::new(&recipient_keys.npk(), &expected_private_account_2),
|
||||||
];
|
];
|
||||||
|
|
||||||
let mut commitment_set = CommitmentSet::with_capacity(2);
|
|
||||||
commitment_set.extend(&[commitment_sender.clone()]);
|
|
||||||
|
|
||||||
let (output, proof) = execute_and_prove(
|
let (output, proof) = execute_and_prove(
|
||||||
&[sender_pre.clone(), recipient],
|
&[sender_pre.clone(), recipient],
|
||||||
&Program::serialize_instruction(balance_to_move).unwrap(),
|
&Program::serialize_instruction(balance_to_move).unwrap(),
|
||||||
@ -237,7 +236,6 @@ mod tests {
|
|||||||
commitment_set.get_proof_for(&commitment_sender).unwrap(),
|
commitment_set.get_proof_for(&commitment_sender).unwrap(),
|
||||||
)],
|
)],
|
||||||
&program,
|
&program,
|
||||||
&commitment_set.digest(),
|
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -246,7 +244,6 @@ mod tests {
|
|||||||
assert!(output.public_post_states.is_empty());
|
assert!(output.public_post_states.is_empty());
|
||||||
assert_eq!(output.new_commitments, expected_new_commitments);
|
assert_eq!(output.new_commitments, expected_new_commitments);
|
||||||
assert_eq!(output.new_nullifiers, expected_new_nullifiers);
|
assert_eq!(output.new_nullifiers, expected_new_nullifiers);
|
||||||
assert_eq!(output.commitment_set_digest, commitment_set.digest());
|
|
||||||
assert_eq!(output.encrypted_private_post_states.len(), 2);
|
assert_eq!(output.encrypted_private_post_states.len(), 2);
|
||||||
|
|
||||||
let recipient_post_1 = output.encrypted_private_post_states[0]
|
let recipient_post_1 = output.encrypted_private_post_states[0]
|
||||||
|
|||||||
@ -12,8 +12,7 @@ use crate::{Address, error::NssaError};
|
|||||||
use super::message::Message;
|
use super::message::Message;
|
||||||
|
|
||||||
const MESSAGE_ENCODING_PREFIX_LEN: usize = 22;
|
const MESSAGE_ENCODING_PREFIX_LEN: usize = 22;
|
||||||
const MESSAGE_ENCODING_PREFIX: &[u8; MESSAGE_ENCODING_PREFIX_LEN] =
|
const MESSAGE_ENCODING_PREFIX: &[u8; MESSAGE_ENCODING_PREFIX_LEN] = b"\x01/NSSA/v0.1/TxMessage/";
|
||||||
b"\x01/NSSA/v0.1/TxMessage/";
|
|
||||||
|
|
||||||
impl Message {
|
impl Message {
|
||||||
pub(crate) fn to_bytes(&self) -> Vec<u8> {
|
pub(crate) fn to_bytes(&self) -> Vec<u8> {
|
||||||
@ -56,9 +55,11 @@ impl Message {
|
|||||||
// New nullifiers
|
// New nullifiers
|
||||||
let new_nullifiers_len: u32 = self.new_nullifiers.len() as u32;
|
let new_nullifiers_len: u32 = self.new_nullifiers.len() as u32;
|
||||||
bytes.extend_from_slice(&new_nullifiers_len.to_le_bytes());
|
bytes.extend_from_slice(&new_nullifiers_len.to_le_bytes());
|
||||||
for nullifier in &self.new_nullifiers {
|
for (nullifier, commitment_set_digest) in &self.new_nullifiers {
|
||||||
bytes.extend_from_slice(&nullifier.to_byte_array());
|
bytes.extend_from_slice(&nullifier.to_byte_array());
|
||||||
|
bytes.extend_from_slice(commitment_set_digest);
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes
|
bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,7 +126,10 @@ impl Message {
|
|||||||
let new_nullifiers_len = u32::from_le_bytes(len_bytes) as usize;
|
let new_nullifiers_len = u32::from_le_bytes(len_bytes) as usize;
|
||||||
let mut new_nullifiers = Vec::with_capacity(new_nullifiers_len);
|
let mut new_nullifiers = Vec::with_capacity(new_nullifiers_len);
|
||||||
for _ in 0..new_nullifiers_len {
|
for _ in 0..new_nullifiers_len {
|
||||||
new_nullifiers.push(Nullifier::from_cursor(cursor)?);
|
let nullifier = Nullifier::from_cursor(cursor)?;
|
||||||
|
let mut commitment_set_digest = [0; 32];
|
||||||
|
cursor.read_exact(&mut commitment_set_digest);
|
||||||
|
new_nullifiers.push((nullifier, commitment_set_digest));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
use nssa_core::{
|
use nssa_core::{
|
||||||
EncryptedAccountData,
|
CommitmentSetDigest, EncryptedAccountData,
|
||||||
account::{Account, Commitment, Nonce, Nullifier},
|
account::{Account, Commitment, Nonce, Nullifier},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ pub struct Message {
|
|||||||
pub(crate) public_post_states: Vec<Account>,
|
pub(crate) public_post_states: Vec<Account>,
|
||||||
pub(crate) encrypted_private_post_states: Vec<EncryptedAccountData>,
|
pub(crate) encrypted_private_post_states: Vec<EncryptedAccountData>,
|
||||||
pub(crate) new_commitments: Vec<Commitment>,
|
pub(crate) new_commitments: Vec<Commitment>,
|
||||||
pub(crate) new_nullifiers: Vec<Nullifier>,
|
pub(crate) new_nullifiers: Vec<(Nullifier, CommitmentSetDigest)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Message {
|
impl Message {
|
||||||
@ -22,7 +22,7 @@ impl Message {
|
|||||||
public_post_states: Vec<Account>,
|
public_post_states: Vec<Account>,
|
||||||
encrypted_private_post_states: Vec<EncryptedAccountData>,
|
encrypted_private_post_states: Vec<EncryptedAccountData>,
|
||||||
new_commitments: Vec<Commitment>,
|
new_commitments: Vec<Commitment>,
|
||||||
new_nullifiers: Vec<Nullifier>,
|
new_nullifiers: Vec<(Nullifier, CommitmentSetDigest)>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
public_addresses,
|
public_addresses,
|
||||||
@ -66,7 +66,7 @@ pub mod tests {
|
|||||||
let new_commitments = vec![Commitment::new(&Npk2, &account2)];
|
let new_commitments = vec![Commitment::new(&Npk2, &account2)];
|
||||||
|
|
||||||
let old_commitment = Commitment::new(&Npk1, &account1);
|
let old_commitment = Commitment::new(&Npk1, &account1);
|
||||||
let new_nullifiers = vec![Nullifier::new(&old_commitment, &nsk1)];
|
let new_nullifiers = vec![(Nullifier::new(&old_commitment, &nsk1), [0; 32])];
|
||||||
|
|
||||||
Message {
|
Message {
|
||||||
public_addresses: public_addresses.clone(),
|
public_addresses: public_addresses.clone(),
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
use nssa_core::account::{Account, AccountWithMetadata};
|
use nssa_core::account::{Account, AccountWithMetadata, Commitment, Nullifier};
|
||||||
use nssa_core::{CommitmentSetDigest, EncryptedAccountData, PrivacyPreservingCircuitOutput};
|
use nssa_core::{CommitmentSetDigest, EncryptedAccountData, PrivacyPreservingCircuitOutput};
|
||||||
|
|
||||||
use crate::error::NssaError;
|
use crate::error::NssaError;
|
||||||
@ -93,8 +93,6 @@ impl PrivacyPreservingTransaction {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let set_commitment = state.commitment_set_digest();
|
|
||||||
|
|
||||||
// 4. Proof verification
|
// 4. Proof verification
|
||||||
check_privacy_preserving_circuit_proof_is_valid(
|
check_privacy_preserving_circuit_proof_is_valid(
|
||||||
&witness_set.proof,
|
&witness_set.proof,
|
||||||
@ -103,14 +101,13 @@ impl PrivacyPreservingTransaction {
|
|||||||
&message.encrypted_private_post_states,
|
&message.encrypted_private_post_states,
|
||||||
&message.new_commitments,
|
&message.new_commitments,
|
||||||
&message.new_nullifiers,
|
&message.new_nullifiers,
|
||||||
set_commitment,
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// 5. Commitment freshness
|
// 5. Commitment freshness
|
||||||
state.check_commitments_are_new(&message.new_commitments)?;
|
state.check_commitments_are_new(&message.new_commitments)?;
|
||||||
|
|
||||||
// 6. Nullifier uniqueness
|
// 6. Nullifier uniqueness
|
||||||
state.check_nullifiers_are_new(&message.new_nullifiers)?;
|
state.check_nullifiers_are_valid(&message.new_nullifiers)?;
|
||||||
|
|
||||||
Ok(message
|
Ok(message
|
||||||
.public_addresses
|
.public_addresses
|
||||||
@ -142,9 +139,8 @@ fn check_privacy_preserving_circuit_proof_is_valid(
|
|||||||
public_pre_states: &[AccountWithMetadata],
|
public_pre_states: &[AccountWithMetadata],
|
||||||
public_post_states: &[Account],
|
public_post_states: &[Account],
|
||||||
encrypted_private_post_states: &[EncryptedAccountData],
|
encrypted_private_post_states: &[EncryptedAccountData],
|
||||||
new_commitments: &[nssa_core::account::Commitment],
|
new_commitments: &[Commitment],
|
||||||
new_nullifiers: &[nssa_core::account::Nullifier],
|
new_nullifiers: &[(Nullifier, CommitmentSetDigest)],
|
||||||
commitment_set_digest: CommitmentSetDigest,
|
|
||||||
) -> Result<(), NssaError> {
|
) -> Result<(), NssaError> {
|
||||||
let output = PrivacyPreservingCircuitOutput {
|
let output = PrivacyPreservingCircuitOutput {
|
||||||
public_pre_states: public_pre_states.to_vec(),
|
public_pre_states: public_pre_states.to_vec(),
|
||||||
@ -152,7 +148,6 @@ fn check_privacy_preserving_circuit_proof_is_valid(
|
|||||||
encrypted_private_post_states: encrypted_private_post_states.to_vec(),
|
encrypted_private_post_states: encrypted_private_post_states.to_vec(),
|
||||||
new_commitments: new_commitments.to_vec(),
|
new_commitments: new_commitments.to_vec(),
|
||||||
new_nullifiers: new_nullifiers.to_vec(),
|
new_nullifiers: new_nullifiers.to_vec(),
|
||||||
commitment_set_digest,
|
|
||||||
};
|
};
|
||||||
proof
|
proof
|
||||||
.is_valid_for(&output)
|
.is_valid_for(&output)
|
||||||
|
|||||||
@ -13,6 +13,7 @@ use std::collections::{HashMap, HashSet};
|
|||||||
pub(crate) struct CommitmentSet {
|
pub(crate) struct CommitmentSet {
|
||||||
merkle_tree: MerkleTree,
|
merkle_tree: MerkleTree,
|
||||||
commitments: HashMap<Commitment, usize>,
|
commitments: HashMap<Commitment, usize>,
|
||||||
|
pub root_history: HashSet<CommitmentSetDigest>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CommitmentSet {
|
impl CommitmentSet {
|
||||||
@ -22,9 +23,11 @@ impl CommitmentSet {
|
|||||||
|
|
||||||
pub(crate) fn get_proof_for(&self, commitment: &Commitment) -> Option<MembershipProof> {
|
pub(crate) fn get_proof_for(&self, commitment: &Commitment) -> Option<MembershipProof> {
|
||||||
let index = *self.commitments.get(commitment)?;
|
let index = *self.commitments.get(commitment)?;
|
||||||
self.merkle_tree
|
let proof = self
|
||||||
|
.merkle_tree
|
||||||
.get_authentication_path_for(index)
|
.get_authentication_path_for(index)
|
||||||
.map(|path| (index, path))
|
.map(|path| (index, path));
|
||||||
|
proof
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn extend(&mut self, commitments: &[Commitment]) {
|
pub(crate) fn extend(&mut self, commitments: &[Commitment]) {
|
||||||
@ -32,6 +35,7 @@ impl CommitmentSet {
|
|||||||
let index = self.merkle_tree.insert(commitment.to_byte_array());
|
let index = self.merkle_tree.insert(commitment.to_byte_array());
|
||||||
self.commitments.insert(commitment, index);
|
self.commitments.insert(commitment, index);
|
||||||
}
|
}
|
||||||
|
self.root_history.insert(self.digest());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn contains(&self, commitment: &Commitment) -> bool {
|
fn contains(&self, commitment: &Commitment) -> bool {
|
||||||
@ -42,6 +46,7 @@ impl CommitmentSet {
|
|||||||
Self {
|
Self {
|
||||||
merkle_tree: MerkleTree::with_capacity(capacity),
|
merkle_tree: MerkleTree::with_capacity(capacity),
|
||||||
commitments: HashMap::new(),
|
commitments: HashMap::new(),
|
||||||
|
root_history: HashSet::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -50,7 +55,7 @@ type NullifierSet = HashSet<Nullifier>;
|
|||||||
|
|
||||||
pub struct V01State {
|
pub struct V01State {
|
||||||
public_state: HashMap<Address, Account>,
|
public_state: HashMap<Address, Account>,
|
||||||
private_state: (CommitmentSet, NullifierSet),
|
pub private_state: (CommitmentSet, NullifierSet),
|
||||||
builtin_programs: HashMap<ProgramId, Program>,
|
builtin_programs: HashMap<ProgramId, Program>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,7 +127,13 @@ impl V01State {
|
|||||||
self.private_state.0.extend(&message.new_commitments);
|
self.private_state.0.extend(&message.new_commitments);
|
||||||
|
|
||||||
// 3. Add new nullifiers
|
// 3. Add new nullifiers
|
||||||
self.private_state.1.extend(message.new_nullifiers.clone());
|
let new_nullifiers = message
|
||||||
|
.new_nullifiers
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.map(|(nullifier, _)| nullifier)
|
||||||
|
.collect::<Vec<Nullifier>>();
|
||||||
|
self.private_state.1.extend(new_nullifiers);
|
||||||
|
|
||||||
// 4. Update public accounts
|
// 4. Update public accounts
|
||||||
for (address, post) in public_state_diff.into_iter() {
|
for (address, post) in public_state_diff.into_iter() {
|
||||||
@ -172,19 +183,34 @@ impl V01State {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn check_nullifiers_are_new(
|
pub(crate) fn check_nullifiers_are_valid(
|
||||||
&self,
|
&self,
|
||||||
new_nullifiers: &[Nullifier],
|
new_nullifiers: &[(Nullifier, CommitmentSetDigest)],
|
||||||
) -> Result<(), NssaError> {
|
) -> Result<(), NssaError> {
|
||||||
for nullifier in new_nullifiers.iter() {
|
for (nullifier, digest) in new_nullifiers.iter() {
|
||||||
if self.private_state.1.contains(nullifier) {
|
if self.private_state.1.contains(nullifier) {
|
||||||
return Err(NssaError::InvalidInput(
|
return Err(NssaError::InvalidInput(
|
||||||
"Nullifier already seen".to_string(),
|
"Nullifier already seen".to_string(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
if !self.private_state.0.root_history.contains(digest) {
|
||||||
|
return Err(NssaError::InvalidInput(
|
||||||
|
"Unrecognized commitment set digest".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn check_commitment_set_digest_is_valid(
|
||||||
|
&self,
|
||||||
|
commitment_set_digest: &CommitmentSetDigest,
|
||||||
|
) -> bool {
|
||||||
|
self.private_state
|
||||||
|
.0
|
||||||
|
.root_history
|
||||||
|
.contains(commitment_set_digest)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -774,7 +800,6 @@ pub mod tests {
|
|||||||
&[(recipient_keys.npk(), recipient_keys.ivk(), esk)],
|
&[(recipient_keys.npk(), recipient_keys.ivk(), esk)],
|
||||||
&[],
|
&[],
|
||||||
&Program::authenticated_transfer_program(),
|
&Program::authenticated_transfer_program(),
|
||||||
&state.commitment_set_digest(),
|
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -828,7 +853,6 @@ pub mod tests {
|
|||||||
.unwrap(),
|
.unwrap(),
|
||||||
)],
|
)],
|
||||||
&program,
|
&program,
|
||||||
&state.private_state.0.digest(),
|
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -880,7 +904,6 @@ pub mod tests {
|
|||||||
.unwrap(),
|
.unwrap(),
|
||||||
)],
|
)],
|
||||||
&program,
|
&program,
|
||||||
&state.private_state.0.digest(),
|
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user