mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-01-03 13:53:12 +00:00
add priv preserving tx validation criteria scaffolding
This commit is contained in:
parent
507988832f
commit
1a10dade25
@ -3,14 +3,14 @@ use nssa_core::account::{Account, Commitment, Nonce, Nullifier};
|
||||
use crate::Address;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
struct EncryptedAccountData;
|
||||
pub struct EncryptedAccountData;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Message {
|
||||
pub(crate) public_addresses: Vec<Address>,
|
||||
pub(crate) nonces: Vec<Nonce>,
|
||||
pub(crate) public_post_states: Vec<Account>,
|
||||
pub(crate) encrypted_private_post_states: Vec<EncryptedAccountData>,
|
||||
pub(crate) encrypted_private_post_states: EncryptedAccountData,
|
||||
pub(crate) new_commitments: Vec<Commitment>,
|
||||
pub(crate) new_nullifiers: Vec<Nullifier>,
|
||||
}
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use nssa_core::account::Account;
|
||||
use nssa_core::account::{Account, AccountWithMetadata};
|
||||
|
||||
use crate::error::NssaError;
|
||||
use crate::privacy_preserving_transaction::message::EncryptedAccountData;
|
||||
use crate::state::CommitmentSetDigest;
|
||||
use crate::{Address, V01State};
|
||||
|
||||
use super::message::Message;
|
||||
@ -15,11 +17,100 @@ pub struct PrivacyPreservingTransaction {
|
||||
}
|
||||
|
||||
impl PrivacyPreservingTransaction {
|
||||
pub(crate) fn validate(
|
||||
pub(crate) fn validate_and_produce_public_state_diff(
|
||||
&self,
|
||||
arg: &mut V01State,
|
||||
state: &mut V01State,
|
||||
) -> Result<HashMap<Address, Account>, NssaError> {
|
||||
todo!()
|
||||
let message = &self.message;
|
||||
let witness_set = &self.witness_set;
|
||||
|
||||
// 1. Commitments or nullifiers are non empty
|
||||
if message.new_commitments.is_empty() && message.new_nullifiers.is_empty() {
|
||||
return Err(NssaError::InvalidInput(
|
||||
"Empty commitments and empty nullifiers found in message".into(),
|
||||
));
|
||||
}
|
||||
|
||||
// 2. Check there are no duplicate addresses in the public_addresses list.
|
||||
if n_unique(&message.public_addresses) != message.public_addresses.len() {
|
||||
return Err(NssaError::InvalidInput(
|
||||
"Duplicate addresses found in message".into(),
|
||||
));
|
||||
}
|
||||
|
||||
// Check there are no duplicate nullifiers in the new_nullifiers list
|
||||
if n_unique(&message.new_nullifiers) != message.new_nullifiers.len() {
|
||||
return Err(NssaError::InvalidInput(
|
||||
"Duplicate nullifiers found in message".into(),
|
||||
));
|
||||
}
|
||||
|
||||
// Check there are no duplicate commitments in the new_nullifiers list
|
||||
if n_unique(&message.new_commitments) != message.new_commitments.len() {
|
||||
return Err(NssaError::InvalidInput(
|
||||
"Duplicate commitments found in message".into(),
|
||||
));
|
||||
}
|
||||
|
||||
// 3. Nonce checks and Valid signatures
|
||||
// Check exactly one nonce is provided for each signature
|
||||
if message.nonces.len() != witness_set.signatures_and_public_keys.len() {
|
||||
return Err(NssaError::InvalidInput(
|
||||
"Mismatch between number of nonces and signatures/public keys".into(),
|
||||
));
|
||||
}
|
||||
|
||||
// Check the signatures are valid
|
||||
if !witness_set.is_valid_for(message) {
|
||||
return Err(NssaError::InvalidInput(
|
||||
"Invalid signature for given message and public key".into(),
|
||||
));
|
||||
}
|
||||
|
||||
let signer_addresses = self.signer_addresses();
|
||||
// Check nonces corresponds to the current nonces on the public state.
|
||||
for (address, nonce) in signer_addresses.iter().zip(&message.nonces) {
|
||||
let current_nonce = state.get_account_by_address(address).nonce;
|
||||
if current_nonce != *nonce {
|
||||
return Err(NssaError::InvalidInput("Nonce mismatch".into()));
|
||||
}
|
||||
}
|
||||
|
||||
// Build pre_states for proof verification
|
||||
let public_pre_states: Vec<_> = message
|
||||
.public_addresses
|
||||
.iter()
|
||||
.map(|address| AccountWithMetadata {
|
||||
account: state.get_account_by_address(address),
|
||||
is_authorized: signer_addresses.contains(address),
|
||||
})
|
||||
.collect();
|
||||
|
||||
let set_commitment = state.commitment_set_digest();
|
||||
|
||||
// 4. Proof verification
|
||||
check_privacy_preserving_circuit_execution_proof_is_valid(
|
||||
witness_set.proof,
|
||||
&public_pre_states,
|
||||
&message.public_post_states,
|
||||
&message.encrypted_private_post_states,
|
||||
&message.new_commitments,
|
||||
&message.new_nullifiers,
|
||||
set_commitment,
|
||||
)?;
|
||||
|
||||
// 5. Commitment freshness
|
||||
state.check_commitments_are_new(&message.new_commitments)?;
|
||||
|
||||
// 6. Nullifier uniqueness
|
||||
state.check_nullifiers_are_new(&message.new_nullifiers)?;
|
||||
|
||||
Ok(message
|
||||
.public_addresses
|
||||
.iter()
|
||||
.cloned()
|
||||
.zip(message.public_post_states.clone())
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub fn message(&self) -> &Message {
|
||||
@ -38,3 +129,21 @@ impl PrivacyPreservingTransaction {
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
fn check_privacy_preserving_circuit_execution_proof_is_valid(
|
||||
proof: (),
|
||||
public_pre_states: &[AccountWithMetadata],
|
||||
public_post_states: &[Account],
|
||||
encrypted_private_post_states: &EncryptedAccountData,
|
||||
new_commitments: &[nssa_core::account::Commitment],
|
||||
new_nullifiers: &[nssa_core::account::Nullifier],
|
||||
commitment_set_digest: CommitmentSetDigest,
|
||||
) -> Result<(), NssaError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
use std::hash::Hash;
|
||||
fn n_unique<T: Eq + Hash>(data: &[T]) -> usize {
|
||||
let set: HashSet<&T> = data.iter().collect();
|
||||
set.len()
|
||||
}
|
||||
|
||||
@ -1,8 +1,12 @@
|
||||
use crate::{privacy_preserving_transaction::message::Message, PrivateKey, PublicKey, Signature};
|
||||
|
||||
|
||||
type Proof = ();
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct WitnessSet {
|
||||
pub(super) signatures_and_public_keys: Vec<(Signature, PublicKey)>,
|
||||
pub(super) proof: Proof
|
||||
}
|
||||
|
||||
|
||||
@ -18,4 +22,8 @@ impl WitnessSet {
|
||||
pub fn signatures_and_public_keys(&self) -> &[(Signature, PublicKey)] {
|
||||
&self.signatures_and_public_keys
|
||||
}
|
||||
|
||||
pub fn proof(&self) -> &Proof {
|
||||
&self.proof
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,7 +50,7 @@ impl PublicTransaction {
|
||||
hasher.finalize_fixed().into()
|
||||
}
|
||||
|
||||
pub(crate) fn validate_and_compute_post_states(
|
||||
pub(crate) fn validate_and_produce_public_state_diff(
|
||||
&self,
|
||||
state: &V01State,
|
||||
) -> Result<HashMap<Address, Account>, NssaError> {
|
||||
@ -64,6 +64,7 @@ impl PublicTransaction {
|
||||
));
|
||||
}
|
||||
|
||||
// Check exactly one nonce is provided for each signature
|
||||
if message.nonces.len() != witness_set.signatures_and_public_keys.len() {
|
||||
return Err(NssaError::InvalidInput(
|
||||
"Mismatch between number of nonces and signatures/public keys".into(),
|
||||
@ -232,7 +233,7 @@ pub mod tests {
|
||||
|
||||
let witness_set = WitnessSet::for_message(&message, &[&key1, &key1]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
let result = tx.validate_and_compute_post_states(&state);
|
||||
let result = tx.validate_and_produce_public_state_diff(&state);
|
||||
assert!(matches!(result, Err(NssaError::InvalidInput(_))))
|
||||
}
|
||||
|
||||
@ -252,7 +253,7 @@ pub mod tests {
|
||||
|
||||
let witness_set = WitnessSet::for_message(&message, &[&key1, &key2]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
let result = tx.validate_and_compute_post_states(&state);
|
||||
let result = tx.validate_and_produce_public_state_diff(&state);
|
||||
assert!(matches!(result, Err(NssaError::InvalidInput(_))))
|
||||
}
|
||||
|
||||
@ -273,7 +274,7 @@ pub mod tests {
|
||||
let mut witness_set = WitnessSet::for_message(&message, &[&key1, &key2]);
|
||||
witness_set.signatures_and_public_keys[0].0 = Signature::new_for_tests([1; 64]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
let result = tx.validate_and_compute_post_states(&state);
|
||||
let result = tx.validate_and_produce_public_state_diff(&state);
|
||||
assert!(matches!(result, Err(NssaError::InvalidInput(_))))
|
||||
}
|
||||
|
||||
@ -293,7 +294,7 @@ pub mod tests {
|
||||
|
||||
let witness_set = WitnessSet::for_message(&message, &[&key1, &key2]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
let result = tx.validate_and_compute_post_states(&state);
|
||||
let result = tx.validate_and_produce_public_state_diff(&state);
|
||||
assert!(matches!(result, Err(NssaError::InvalidInput(_))))
|
||||
}
|
||||
|
||||
@ -309,7 +310,7 @@ pub mod tests {
|
||||
|
||||
let witness_set = WitnessSet::for_message(&message, &[&key1, &key2]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
let result = tx.validate_and_compute_post_states(&state);
|
||||
let result = tx.validate_and_produce_public_state_diff(&state);
|
||||
assert!(matches!(result, Err(NssaError::InvalidInput(_))))
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,15 +10,16 @@ use nssa_core::{
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
struct CommitmentSet(HashSet<Commitment>);
|
||||
pub type CommitmentSetDigest = [u32; 8];
|
||||
|
||||
impl CommitmentSet {
|
||||
fn extend(&mut self, commitments: &[Commitment]) {
|
||||
fn extend(&mut self, commitments: Vec<Commitment>) {
|
||||
self.0.extend(commitments)
|
||||
}
|
||||
|
||||
fn set_commitment(&self) -> [u8; 32] {
|
||||
fn digest(&self) -> CommitmentSetDigest {
|
||||
// TODO: implement
|
||||
[0; 32]
|
||||
[0; 8]
|
||||
}
|
||||
}
|
||||
type NullifierSet = HashSet<Nullifier>;
|
||||
@ -65,7 +66,7 @@ impl V01State {
|
||||
&mut self,
|
||||
tx: &PublicTransaction,
|
||||
) -> Result<(), NssaError> {
|
||||
let state_diff = tx.validate_and_compute_post_states(self)?;
|
||||
let state_diff = tx.validate_and_produce_public_state_diff(self)?;
|
||||
|
||||
for (address, post) in state_diff.into_iter() {
|
||||
let current_account = self.get_account_by_address_mut(address);
|
||||
@ -90,14 +91,15 @@ impl V01State {
|
||||
tx: &PrivacyPreservingTransaction,
|
||||
) -> Result<(), NssaError> {
|
||||
// 1. Verify the transaction satisfies acceptance criteria
|
||||
let public_state_diff = tx.validate(self)?;
|
||||
let public_state_diff = tx.validate_and_produce_public_state_diff(self)?;
|
||||
|
||||
let message = tx.message();
|
||||
|
||||
// 2. Add new commitments
|
||||
self.private_state.0.extend(message.new_commitments);
|
||||
self.private_state.0.extend(message.new_commitments.clone());
|
||||
|
||||
// 3. Add new nullifiers
|
||||
self.private_state.1.extend(message.new_nullifiers);
|
||||
self.private_state.1.extend(message.new_nullifiers.clone());
|
||||
|
||||
// 4. Update public accounts
|
||||
for (address, post) in public_state_diff.into_iter() {
|
||||
@ -127,6 +129,24 @@ impl V01State {
|
||||
pub(crate) fn builtin_programs(&self) -> &HashMap<ProgramId, Program> {
|
||||
&self.builtin_programs
|
||||
}
|
||||
|
||||
pub fn commitment_set_digest(&self) -> CommitmentSetDigest {
|
||||
self.private_state.0.digest()
|
||||
}
|
||||
|
||||
pub(crate) fn check_commitments_are_new(
|
||||
&self,
|
||||
new_commitments: &[Commitment],
|
||||
) -> Result<(), NssaError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub(crate) fn check_nullifiers_are_new(
|
||||
&self,
|
||||
new_nullifiers: &[Nullifier],
|
||||
) -> Result<(), NssaError> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user