mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-01-07 15:53:14 +00:00
Merge pull request #108 from vacp2p/schouhy/add-privacy-preserving-circuit-tests
Add privacy preserving circuit tests
This commit is contained in:
commit
b7c2e8a3ec
@ -32,11 +32,13 @@ fn main() {
|
|||||||
|
|
||||||
// Check that the program is well behaved.
|
// Check that the program is well behaved.
|
||||||
// See the # Programs section for the definition of the `validate_execution` method.
|
// See the # Programs section for the definition of the `validate_execution` method.
|
||||||
validate_execution(&pre_states, &post_states, program_id);
|
if !validate_execution(&pre_states, &post_states, program_id) {
|
||||||
|
panic!("Bad behaved program");
|
||||||
|
}
|
||||||
|
|
||||||
let n_accounts = pre_states.len();
|
let n_accounts = pre_states.len();
|
||||||
if visibility_mask.len() != n_accounts {
|
if visibility_mask.len() != n_accounts {
|
||||||
panic!();
|
panic!("Invalid visibility mask length");
|
||||||
}
|
}
|
||||||
|
|
||||||
// These lists will be the public outputs of this circuit
|
// These lists will be the public outputs of this circuit
|
||||||
@ -59,7 +61,9 @@ fn main() {
|
|||||||
public_pre_states.push(pre_states[i].clone());
|
public_pre_states.push(pre_states[i].clone());
|
||||||
|
|
||||||
let mut post = post_states[i].clone();
|
let mut post = post_states[i].clone();
|
||||||
|
if pre_states[i].is_authorized {
|
||||||
post.nonce += 1;
|
post.nonce += 1;
|
||||||
|
}
|
||||||
if post.program_owner == DEFAULT_PROGRAM_ID {
|
if post.program_owner == DEFAULT_PROGRAM_ID {
|
||||||
// Claim account
|
// Claim account
|
||||||
post.program_owner = program_id;
|
post.program_owner = program_id;
|
||||||
@ -136,7 +140,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if private_keys_iter.next().is_some() {
|
if private_keys_iter.next().is_some() {
|
||||||
panic!("Too many private accounts keys.");
|
panic!("Too many private account keys.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if private_auth_iter.next().is_some() {
|
if private_auth_iter.next().is_some() {
|
||||||
|
|||||||
@ -45,4 +45,7 @@ pub enum NssaError {
|
|||||||
|
|
||||||
#[error("Invalid privacy preserving execution circuit proof")]
|
#[error("Invalid privacy preserving execution circuit proof")]
|
||||||
InvalidPrivacyPreservingProof,
|
InvalidPrivacyPreservingProof,
|
||||||
|
|
||||||
|
#[error("Circuit proving error")]
|
||||||
|
CircuitProvingError(String),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,7 +47,9 @@ pub fn execute_and_prove(
|
|||||||
env_builder.write(&circuit_input).unwrap();
|
env_builder.write(&circuit_input).unwrap();
|
||||||
let env = env_builder.build().unwrap();
|
let env = env_builder.build().unwrap();
|
||||||
let prover = default_prover();
|
let prover = default_prover();
|
||||||
let prove_info = prover.prove(env, PRIVACY_PRESERVING_CIRCUIT_ELF).unwrap();
|
let prove_info = prover
|
||||||
|
.prove(env, PRIVACY_PRESERVING_CIRCUIT_ELF)
|
||||||
|
.map_err(|e| NssaError::CircuitProvingError(e.to_string()))?;
|
||||||
|
|
||||||
let proof = Proof(borsh::to_vec(&prove_info.receipt.inner)?);
|
let proof = Proof(borsh::to_vec(&prove_info.receipt.inner)?);
|
||||||
|
|
||||||
@ -109,6 +111,7 @@ mod tests {
|
|||||||
let program = Program::authenticated_transfer_program();
|
let program = Program::authenticated_transfer_program();
|
||||||
let sender = AccountWithMetadata {
|
let sender = AccountWithMetadata {
|
||||||
account: Account {
|
account: Account {
|
||||||
|
program_owner: program.id(),
|
||||||
balance: 100,
|
balance: 100,
|
||||||
..Account::default()
|
..Account::default()
|
||||||
},
|
},
|
||||||
@ -175,11 +178,13 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn prove_privacy_preserving_execution_circuit_fully_private() {
|
fn prove_privacy_preserving_execution_circuit_fully_private() {
|
||||||
|
let program = Program::authenticated_transfer_program();
|
||||||
let sender_pre = AccountWithMetadata {
|
let sender_pre = AccountWithMetadata {
|
||||||
account: Account {
|
account: Account {
|
||||||
balance: 100,
|
balance: 100,
|
||||||
nonce: 0xdeadbeef,
|
nonce: 0xdeadbeef,
|
||||||
..Account::default()
|
program_owner: program.id(),
|
||||||
|
data: vec![],
|
||||||
},
|
},
|
||||||
is_authorized: true,
|
is_authorized: true,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -145,12 +145,6 @@ impl V01State {
|
|||||||
*current_account = post;
|
*current_account = post;
|
||||||
}
|
}
|
||||||
|
|
||||||
// // 5. Increment nonces
|
|
||||||
for address in tx.signer_addresses() {
|
|
||||||
let current_account = self.get_account_by_address_mut(address);
|
|
||||||
current_account.nonce += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,6 +213,7 @@ pub mod tests {
|
|||||||
use crate::{
|
use crate::{
|
||||||
Address, PublicKey, PublicTransaction, V01State,
|
Address, PublicKey, PublicTransaction, V01State,
|
||||||
error::NssaError,
|
error::NssaError,
|
||||||
|
execute_and_prove,
|
||||||
privacy_preserving_transaction::{
|
privacy_preserving_transaction::{
|
||||||
PrivacyPreservingTransaction, circuit, message::Message, witness_set::WitnessSet,
|
PrivacyPreservingTransaction, circuit, message::Message, witness_set::WitnessSet,
|
||||||
},
|
},
|
||||||
@ -941,6 +936,13 @@ pub mod tests {
|
|||||||
&state,
|
&state,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let expected_sender_post = {
|
||||||
|
let mut this = state.get_account_by_address(&sender_keys.address());
|
||||||
|
this.balance -= balance_to_move;
|
||||||
|
this.nonce += 1;
|
||||||
|
this
|
||||||
|
};
|
||||||
|
|
||||||
let [expected_new_commitment] = tx.message().new_commitments.clone().try_into().unwrap();
|
let [expected_new_commitment] = tx.message().new_commitments.clone().try_into().unwrap();
|
||||||
assert!(!state.private_state.0.contains(&expected_new_commitment));
|
assert!(!state.private_state.0.contains(&expected_new_commitment));
|
||||||
|
|
||||||
@ -948,6 +950,8 @@ pub mod tests {
|
|||||||
.transition_from_privacy_preserving_transaction(&tx)
|
.transition_from_privacy_preserving_transaction(&tx)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let sender_post = state.get_account_by_address(&sender_keys.address());
|
||||||
|
assert_eq!(sender_post, expected_sender_post);
|
||||||
assert!(state.private_state.0.contains(&expected_new_commitment));
|
assert!(state.private_state.0.contains(&expected_new_commitment));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -1040,6 +1044,12 @@ pub mod tests {
|
|||||||
|
|
||||||
let balance_to_move = 37;
|
let balance_to_move = 37;
|
||||||
|
|
||||||
|
let expected_recipient_post = {
|
||||||
|
let mut this = state.get_account_by_address(&recipient_keys.address());
|
||||||
|
this.balance += balance_to_move;
|
||||||
|
this
|
||||||
|
};
|
||||||
|
|
||||||
let tx = deshielded_balance_transfer_for_tests(
|
let tx = deshielded_balance_transfer_for_tests(
|
||||||
&sender_keys,
|
&sender_keys,
|
||||||
&sender_private_account,
|
&sender_private_account,
|
||||||
@ -1070,6 +1080,8 @@ pub mod tests {
|
|||||||
.transition_from_privacy_preserving_transaction(&tx)
|
.transition_from_privacy_preserving_transaction(&tx)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let recipient_post = state.get_account_by_address(&recipient_keys.address());
|
||||||
|
assert_eq!(recipient_post, expected_recipient_post);
|
||||||
assert!(state.private_state.0.contains(&sender_pre_commitment));
|
assert!(state.private_state.0.contains(&sender_pre_commitment));
|
||||||
assert!(state.private_state.0.contains(&expected_new_commitment));
|
assert!(state.private_state.0.contains(&expected_new_commitment));
|
||||||
assert!(state.private_state.1.contains(&expected_new_nullifier));
|
assert!(state.private_state.1.contains(&expected_new_nullifier));
|
||||||
@ -1080,4 +1092,809 @@ pub mod tests {
|
|||||||
recipient_initial_balance + balance_to_move
|
recipient_initial_balance + balance_to_move
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_burner_program_should_fail_in_privacy_preserving_circuit() {
|
||||||
|
let program = Program::burner();
|
||||||
|
let public_account = AccountWithMetadata {
|
||||||
|
account: Account {
|
||||||
|
program_owner: program.id(),
|
||||||
|
balance: 100,
|
||||||
|
..Account::default()
|
||||||
|
},
|
||||||
|
is_authorized: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = execute_and_prove(
|
||||||
|
&[public_account],
|
||||||
|
&Program::serialize_instruction(10u128).unwrap(),
|
||||||
|
&[0],
|
||||||
|
&[],
|
||||||
|
&[],
|
||||||
|
&[],
|
||||||
|
&program,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::CircuitProvingError(_))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_minter_program_should_fail_in_privacy_preserving_circuit() {
|
||||||
|
let program = Program::minter();
|
||||||
|
let public_account = AccountWithMetadata {
|
||||||
|
account: Account {
|
||||||
|
program_owner: program.id(),
|
||||||
|
balance: 0,
|
||||||
|
..Account::default()
|
||||||
|
},
|
||||||
|
is_authorized: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = execute_and_prove(
|
||||||
|
&[public_account],
|
||||||
|
&Program::serialize_instruction(10u128).unwrap(),
|
||||||
|
&[0],
|
||||||
|
&[],
|
||||||
|
&[],
|
||||||
|
&[],
|
||||||
|
&program,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::CircuitProvingError(_))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_nonce_changer_program_should_fail_in_privacy_preserving_circuit() {
|
||||||
|
let program = Program::nonce_changer_program();
|
||||||
|
let public_account = AccountWithMetadata {
|
||||||
|
account: Account {
|
||||||
|
program_owner: program.id(),
|
||||||
|
balance: 0,
|
||||||
|
..Account::default()
|
||||||
|
},
|
||||||
|
is_authorized: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = execute_and_prove(
|
||||||
|
&[public_account],
|
||||||
|
&Program::serialize_instruction(()).unwrap(),
|
||||||
|
&[0],
|
||||||
|
&[],
|
||||||
|
&[],
|
||||||
|
&[],
|
||||||
|
&program,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::CircuitProvingError(_))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_data_changer_program_should_fail_for_non_owned_account_in_privacy_preserving_circuit() {
|
||||||
|
let program = Program::data_changer();
|
||||||
|
let public_account = AccountWithMetadata {
|
||||||
|
account: Account {
|
||||||
|
program_owner: [0, 1, 2, 3, 4, 5, 6, 7],
|
||||||
|
balance: 0,
|
||||||
|
..Account::default()
|
||||||
|
},
|
||||||
|
is_authorized: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = execute_and_prove(
|
||||||
|
&[public_account],
|
||||||
|
&Program::serialize_instruction(()).unwrap(),
|
||||||
|
&[0],
|
||||||
|
&[],
|
||||||
|
&[],
|
||||||
|
&[],
|
||||||
|
&program,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::CircuitProvingError(_))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_extra_output_program_should_fail_in_privacy_preserving_circuit() {
|
||||||
|
let program = Program::extra_output_program();
|
||||||
|
let public_account = AccountWithMetadata {
|
||||||
|
account: Account {
|
||||||
|
program_owner: program.id(),
|
||||||
|
balance: 0,
|
||||||
|
..Account::default()
|
||||||
|
},
|
||||||
|
is_authorized: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = execute_and_prove(
|
||||||
|
&[public_account],
|
||||||
|
&Program::serialize_instruction(()).unwrap(),
|
||||||
|
&[0],
|
||||||
|
&[],
|
||||||
|
&[],
|
||||||
|
&[],
|
||||||
|
&program,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::CircuitProvingError(_))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_missing_output_program_should_fail_in_privacy_preserving_circuit() {
|
||||||
|
let program = Program::missing_output_program();
|
||||||
|
let public_account_1 = AccountWithMetadata {
|
||||||
|
account: Account {
|
||||||
|
program_owner: program.id(),
|
||||||
|
balance: 0,
|
||||||
|
..Account::default()
|
||||||
|
},
|
||||||
|
is_authorized: true,
|
||||||
|
};
|
||||||
|
let public_account_2 = AccountWithMetadata {
|
||||||
|
account: Account {
|
||||||
|
program_owner: program.id(),
|
||||||
|
balance: 0,
|
||||||
|
..Account::default()
|
||||||
|
},
|
||||||
|
is_authorized: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = execute_and_prove(
|
||||||
|
&[public_account_1, public_account_2],
|
||||||
|
&Program::serialize_instruction(()).unwrap(),
|
||||||
|
&[0, 0],
|
||||||
|
&[],
|
||||||
|
&[],
|
||||||
|
&[],
|
||||||
|
&program,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::CircuitProvingError(_))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_program_owner_changer_should_fail_in_privacy_preserving_circuit() {
|
||||||
|
let program = Program::program_owner_changer();
|
||||||
|
let public_account = AccountWithMetadata {
|
||||||
|
account: Account {
|
||||||
|
program_owner: program.id(),
|
||||||
|
balance: 0,
|
||||||
|
..Account::default()
|
||||||
|
},
|
||||||
|
is_authorized: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = execute_and_prove(
|
||||||
|
&[public_account],
|
||||||
|
&Program::serialize_instruction(()).unwrap(),
|
||||||
|
&[0],
|
||||||
|
&[],
|
||||||
|
&[],
|
||||||
|
&[],
|
||||||
|
&program,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::CircuitProvingError(_))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_transfer_from_non_owned_account_should_fail_in_privacy_preserving_circuit() {
|
||||||
|
let program = Program::simple_balance_transfer();
|
||||||
|
let public_account_1 = AccountWithMetadata {
|
||||||
|
account: Account {
|
||||||
|
program_owner: [0, 1, 2, 3, 4, 5, 6, 7],
|
||||||
|
balance: 100,
|
||||||
|
..Account::default()
|
||||||
|
},
|
||||||
|
is_authorized: true,
|
||||||
|
};
|
||||||
|
let public_account_2 = AccountWithMetadata {
|
||||||
|
account: Account {
|
||||||
|
program_owner: program.id(),
|
||||||
|
balance: 0,
|
||||||
|
..Account::default()
|
||||||
|
},
|
||||||
|
is_authorized: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = execute_and_prove(
|
||||||
|
&[public_account_1, public_account_2],
|
||||||
|
&Program::serialize_instruction(10u128).unwrap(),
|
||||||
|
&[0, 0],
|
||||||
|
&[],
|
||||||
|
&[],
|
||||||
|
&[],
|
||||||
|
&program,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::CircuitProvingError(_))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_circuit_fails_if_visibility_masks_have_incorrect_lenght() {
|
||||||
|
let program = Program::simple_balance_transfer();
|
||||||
|
let public_account_1 = AccountWithMetadata {
|
||||||
|
account: Account {
|
||||||
|
program_owner: program.id(),
|
||||||
|
balance: 100,
|
||||||
|
..Account::default()
|
||||||
|
},
|
||||||
|
is_authorized: true,
|
||||||
|
};
|
||||||
|
let public_account_2 = AccountWithMetadata {
|
||||||
|
account: Account {
|
||||||
|
program_owner: program.id(),
|
||||||
|
balance: 0,
|
||||||
|
..Account::default()
|
||||||
|
},
|
||||||
|
is_authorized: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Setting only one visibility mask for a circuit execution with two pre_state accounts.
|
||||||
|
let visibility_mask = [0];
|
||||||
|
let result = execute_and_prove(
|
||||||
|
&[public_account_1, public_account_2],
|
||||||
|
&Program::serialize_instruction(10u128).unwrap(),
|
||||||
|
&visibility_mask,
|
||||||
|
&[],
|
||||||
|
&[],
|
||||||
|
&[],
|
||||||
|
&program,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::CircuitProvingError(_))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_circuit_fails_if_insufficient_nonces_are_provided() {
|
||||||
|
let program = Program::simple_balance_transfer();
|
||||||
|
let sender_keys = test_private_account_keys_1();
|
||||||
|
let recipient_keys = test_private_account_keys_2();
|
||||||
|
let private_account_1 = AccountWithMetadata {
|
||||||
|
account: Account {
|
||||||
|
program_owner: program.id(),
|
||||||
|
balance: 100,
|
||||||
|
..Account::default()
|
||||||
|
},
|
||||||
|
is_authorized: true,
|
||||||
|
};
|
||||||
|
let private_account_2 = AccountWithMetadata {
|
||||||
|
account: Account::default(),
|
||||||
|
is_authorized: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Setting only one nonce for an execution with two private accounts.
|
||||||
|
let private_account_nonces = [0xdeadbeef1];
|
||||||
|
let result = execute_and_prove(
|
||||||
|
&[private_account_1, private_account_2],
|
||||||
|
&Program::serialize_instruction(10u128).unwrap(),
|
||||||
|
&[1, 2],
|
||||||
|
&private_account_nonces,
|
||||||
|
&[
|
||||||
|
(
|
||||||
|
sender_keys.npk(),
|
||||||
|
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
recipient_keys.npk(),
|
||||||
|
SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
&[(sender_keys.nsk, (0, vec![]))],
|
||||||
|
&program,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::CircuitProvingError(_))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_circuit_fails_if_insufficient_keys_are_provided() {
|
||||||
|
let program = Program::simple_balance_transfer();
|
||||||
|
let sender_keys = test_private_account_keys_1();
|
||||||
|
let private_account_1 = AccountWithMetadata {
|
||||||
|
account: Account {
|
||||||
|
program_owner: program.id(),
|
||||||
|
balance: 100,
|
||||||
|
..Account::default()
|
||||||
|
},
|
||||||
|
is_authorized: true,
|
||||||
|
};
|
||||||
|
let private_account_2 = AccountWithMetadata {
|
||||||
|
account: Account::default(),
|
||||||
|
is_authorized: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Setting only one key for an execution with two private accounts.
|
||||||
|
let private_account_keys = [(
|
||||||
|
sender_keys.npk(),
|
||||||
|
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
|
||||||
|
)];
|
||||||
|
let result = execute_and_prove(
|
||||||
|
&[private_account_1, private_account_2],
|
||||||
|
&Program::serialize_instruction(10u128).unwrap(),
|
||||||
|
&[1, 2],
|
||||||
|
&[0xdeadbeef1, 0xdeadbeef2],
|
||||||
|
&private_account_keys,
|
||||||
|
&[(sender_keys.nsk, (0, vec![]))],
|
||||||
|
&program,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::CircuitProvingError(_))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_circuit_fails_if_insufficient_auth_keys_are_provided() {
|
||||||
|
let program = Program::simple_balance_transfer();
|
||||||
|
let sender_keys = test_private_account_keys_1();
|
||||||
|
let recipient_keys = test_private_account_keys_2();
|
||||||
|
let private_account_1 = AccountWithMetadata {
|
||||||
|
account: Account {
|
||||||
|
program_owner: program.id(),
|
||||||
|
balance: 100,
|
||||||
|
..Account::default()
|
||||||
|
},
|
||||||
|
is_authorized: true,
|
||||||
|
};
|
||||||
|
let private_account_2 = AccountWithMetadata {
|
||||||
|
account: Account::default(),
|
||||||
|
is_authorized: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Setting no auth key for an execution with one non default private accounts.
|
||||||
|
let private_account_auth = [];
|
||||||
|
let result = execute_and_prove(
|
||||||
|
&[private_account_1, private_account_2],
|
||||||
|
&Program::serialize_instruction(10u128).unwrap(),
|
||||||
|
&[1, 2],
|
||||||
|
&[0xdeadbeef1, 0xdeadbeef2],
|
||||||
|
&[
|
||||||
|
(
|
||||||
|
sender_keys.npk(),
|
||||||
|
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
recipient_keys.npk(),
|
||||||
|
SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
&private_account_auth,
|
||||||
|
&program,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::CircuitProvingError(_))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_circuit_fails_if_invalid_auth_keys_are_provided() {
|
||||||
|
let program = Program::simple_balance_transfer();
|
||||||
|
let sender_keys = test_private_account_keys_1();
|
||||||
|
let recipient_keys = test_private_account_keys_2();
|
||||||
|
let private_account_1 = AccountWithMetadata {
|
||||||
|
account: Account {
|
||||||
|
program_owner: program.id(),
|
||||||
|
balance: 100,
|
||||||
|
..Account::default()
|
||||||
|
},
|
||||||
|
is_authorized: true,
|
||||||
|
};
|
||||||
|
let private_account_2 = AccountWithMetadata {
|
||||||
|
account: Account::default(),
|
||||||
|
is_authorized: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let private_account_keys = [
|
||||||
|
// First private account is the sender
|
||||||
|
(
|
||||||
|
sender_keys.npk(),
|
||||||
|
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
|
||||||
|
),
|
||||||
|
// Second private account is the recipient
|
||||||
|
(
|
||||||
|
recipient_keys.npk(),
|
||||||
|
SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
let private_account_auth = [
|
||||||
|
// Setting the recipient key to authorize the sender.
|
||||||
|
// This should be set to the sender private account in
|
||||||
|
// a normal circumstance. The recipient can't authorize this.
|
||||||
|
(recipient_keys.nsk, (0, vec![])),
|
||||||
|
];
|
||||||
|
let result = execute_and_prove(
|
||||||
|
&[private_account_1, private_account_2],
|
||||||
|
&Program::serialize_instruction(10u128).unwrap(),
|
||||||
|
&[1, 2],
|
||||||
|
&[0xdeadbeef1, 0xdeadbeef2],
|
||||||
|
&private_account_keys,
|
||||||
|
&private_account_auth,
|
||||||
|
&program,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::CircuitProvingError(_))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_circuit_should_fail_if_new_private_account_with_non_default_balance_is_provided() {
|
||||||
|
let program = Program::simple_balance_transfer();
|
||||||
|
let sender_keys = test_private_account_keys_1();
|
||||||
|
let recipient_keys = test_private_account_keys_2();
|
||||||
|
let private_account_1 = AccountWithMetadata {
|
||||||
|
account: Account {
|
||||||
|
program_owner: program.id(),
|
||||||
|
balance: 100,
|
||||||
|
..Account::default()
|
||||||
|
},
|
||||||
|
is_authorized: true,
|
||||||
|
};
|
||||||
|
let private_account_2 = AccountWithMetadata {
|
||||||
|
account: Account {
|
||||||
|
// Non default balance
|
||||||
|
balance: 1,
|
||||||
|
..Account::default()
|
||||||
|
},
|
||||||
|
is_authorized: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = execute_and_prove(
|
||||||
|
&[private_account_1, private_account_2],
|
||||||
|
&Program::serialize_instruction(10u128).unwrap(),
|
||||||
|
&[1, 2],
|
||||||
|
&[0xdeadbeef1, 0xdeadbeef2],
|
||||||
|
&[
|
||||||
|
(
|
||||||
|
sender_keys.npk(),
|
||||||
|
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
recipient_keys.npk(),
|
||||||
|
SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
&[(sender_keys.nsk, (0, vec![]))],
|
||||||
|
&program,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::CircuitProvingError(_))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_circuit_should_fail_if_new_private_account_with_non_default_program_owner_is_provided()
|
||||||
|
{
|
||||||
|
let program = Program::simple_balance_transfer();
|
||||||
|
let sender_keys = test_private_account_keys_1();
|
||||||
|
let recipient_keys = test_private_account_keys_2();
|
||||||
|
let private_account_1 = AccountWithMetadata {
|
||||||
|
account: Account {
|
||||||
|
program_owner: program.id(),
|
||||||
|
balance: 100,
|
||||||
|
..Account::default()
|
||||||
|
},
|
||||||
|
is_authorized: true,
|
||||||
|
};
|
||||||
|
let private_account_2 = AccountWithMetadata {
|
||||||
|
account: Account {
|
||||||
|
// Non default program_owner
|
||||||
|
program_owner: [0, 1, 2, 3, 4, 5, 6, 7],
|
||||||
|
..Account::default()
|
||||||
|
},
|
||||||
|
is_authorized: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = execute_and_prove(
|
||||||
|
&[private_account_1, private_account_2],
|
||||||
|
&Program::serialize_instruction(10u128).unwrap(),
|
||||||
|
&[1, 2],
|
||||||
|
&[0xdeadbeef1, 0xdeadbeef2],
|
||||||
|
&[
|
||||||
|
(
|
||||||
|
sender_keys.npk(),
|
||||||
|
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
recipient_keys.npk(),
|
||||||
|
SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
&[(sender_keys.nsk, (0, vec![]))],
|
||||||
|
&program,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::CircuitProvingError(_))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_circuit_should_fail_if_new_private_account_with_non_default_data_is_provided() {
|
||||||
|
let program = Program::simple_balance_transfer();
|
||||||
|
let sender_keys = test_private_account_keys_1();
|
||||||
|
let recipient_keys = test_private_account_keys_2();
|
||||||
|
let private_account_1 = AccountWithMetadata {
|
||||||
|
account: Account {
|
||||||
|
program_owner: program.id(),
|
||||||
|
balance: 100,
|
||||||
|
..Account::default()
|
||||||
|
},
|
||||||
|
is_authorized: true,
|
||||||
|
};
|
||||||
|
let private_account_2 = AccountWithMetadata {
|
||||||
|
account: Account {
|
||||||
|
// Non default data
|
||||||
|
data: b"hola mundo".to_vec(),
|
||||||
|
..Account::default()
|
||||||
|
},
|
||||||
|
is_authorized: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = execute_and_prove(
|
||||||
|
&[private_account_1, private_account_2],
|
||||||
|
&Program::serialize_instruction(10u128).unwrap(),
|
||||||
|
&[1, 2],
|
||||||
|
&[0xdeadbeef1, 0xdeadbeef2],
|
||||||
|
&[
|
||||||
|
(
|
||||||
|
sender_keys.npk(),
|
||||||
|
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
recipient_keys.npk(),
|
||||||
|
SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
&[(sender_keys.nsk, (0, vec![]))],
|
||||||
|
&program,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::CircuitProvingError(_))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_circuit_should_fail_if_new_private_account_with_non_default_nonce_is_provided() {
|
||||||
|
let program = Program::simple_balance_transfer();
|
||||||
|
let sender_keys = test_private_account_keys_1();
|
||||||
|
let recipient_keys = test_private_account_keys_2();
|
||||||
|
let private_account_1 = AccountWithMetadata {
|
||||||
|
account: Account {
|
||||||
|
program_owner: program.id(),
|
||||||
|
balance: 100,
|
||||||
|
..Account::default()
|
||||||
|
},
|
||||||
|
is_authorized: true,
|
||||||
|
};
|
||||||
|
let private_account_2 = AccountWithMetadata {
|
||||||
|
account: Account {
|
||||||
|
// Non default nonce
|
||||||
|
nonce: 0xdeadbeef,
|
||||||
|
..Account::default()
|
||||||
|
},
|
||||||
|
is_authorized: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = execute_and_prove(
|
||||||
|
&[private_account_1, private_account_2],
|
||||||
|
&Program::serialize_instruction(10u128).unwrap(),
|
||||||
|
&[1, 2],
|
||||||
|
&[0xdeadbeef1, 0xdeadbeef2],
|
||||||
|
&[
|
||||||
|
(
|
||||||
|
sender_keys.npk(),
|
||||||
|
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
recipient_keys.npk(),
|
||||||
|
SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
&[(sender_keys.nsk, (0, vec![]))],
|
||||||
|
&program,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::CircuitProvingError(_))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_circuit_should_fail_if_new_private_account_is_provided_with_default_values_but_marked_as_authorized()
|
||||||
|
{
|
||||||
|
let program = Program::simple_balance_transfer();
|
||||||
|
let sender_keys = test_private_account_keys_1();
|
||||||
|
let recipient_keys = test_private_account_keys_2();
|
||||||
|
let private_account_1 = AccountWithMetadata {
|
||||||
|
account: Account {
|
||||||
|
program_owner: program.id(),
|
||||||
|
balance: 100,
|
||||||
|
..Account::default()
|
||||||
|
},
|
||||||
|
is_authorized: true,
|
||||||
|
};
|
||||||
|
let private_account_2 = AccountWithMetadata {
|
||||||
|
account: Account::default(),
|
||||||
|
// This should be set to false in normal circumstances
|
||||||
|
is_authorized: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = execute_and_prove(
|
||||||
|
&[private_account_1, private_account_2],
|
||||||
|
&Program::serialize_instruction(10u128).unwrap(),
|
||||||
|
&[1, 2],
|
||||||
|
&[0xdeadbeef1, 0xdeadbeef2],
|
||||||
|
&[
|
||||||
|
(
|
||||||
|
sender_keys.npk(),
|
||||||
|
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
recipient_keys.npk(),
|
||||||
|
SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
&[(sender_keys.nsk, (0, vec![]))],
|
||||||
|
&program,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::CircuitProvingError(_))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_circuit_should_fail_with_invalid_visibility_mask_value() {
|
||||||
|
let program = Program::simple_balance_transfer();
|
||||||
|
let public_account_1 = AccountWithMetadata {
|
||||||
|
account: Account {
|
||||||
|
program_owner: program.id(),
|
||||||
|
balance: 100,
|
||||||
|
..Account::default()
|
||||||
|
},
|
||||||
|
is_authorized: true,
|
||||||
|
};
|
||||||
|
let public_account_2 = AccountWithMetadata {
|
||||||
|
account: Account::default(),
|
||||||
|
is_authorized: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let visibility_mask = [0, 3];
|
||||||
|
let result = execute_and_prove(
|
||||||
|
&[public_account_1, public_account_2],
|
||||||
|
&Program::serialize_instruction(10u128).unwrap(),
|
||||||
|
&visibility_mask,
|
||||||
|
&[],
|
||||||
|
&[],
|
||||||
|
&[],
|
||||||
|
&program,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::CircuitProvingError(_))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_circuit_should_fail_with_too_many_nonces() {
|
||||||
|
let program = Program::simple_balance_transfer();
|
||||||
|
let sender_keys = test_private_account_keys_1();
|
||||||
|
let recipient_keys = test_private_account_keys_2();
|
||||||
|
let private_account_1 = AccountWithMetadata {
|
||||||
|
account: Account {
|
||||||
|
program_owner: program.id(),
|
||||||
|
balance: 100,
|
||||||
|
..Account::default()
|
||||||
|
},
|
||||||
|
is_authorized: true,
|
||||||
|
};
|
||||||
|
let private_account_2 = AccountWithMetadata {
|
||||||
|
account: Account::default(),
|
||||||
|
is_authorized: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Setting three new private account nonces for a circuit execution with only two private
|
||||||
|
// accounts.
|
||||||
|
let private_account_nonces = [0xdeadbeef1, 0xdeadbeef2, 0xdeadbeef3];
|
||||||
|
let result = execute_and_prove(
|
||||||
|
&[private_account_1, private_account_2],
|
||||||
|
&Program::serialize_instruction(10u128).unwrap(),
|
||||||
|
&[1, 2],
|
||||||
|
&private_account_nonces,
|
||||||
|
&[
|
||||||
|
(
|
||||||
|
sender_keys.npk(),
|
||||||
|
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
recipient_keys.npk(),
|
||||||
|
SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
&[(sender_keys.nsk, (0, vec![]))],
|
||||||
|
&program,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::CircuitProvingError(_))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_circuit_should_fail_with_too_many_private_account_keys() {
|
||||||
|
let program = Program::simple_balance_transfer();
|
||||||
|
let sender_keys = test_private_account_keys_1();
|
||||||
|
let recipient_keys = test_private_account_keys_2();
|
||||||
|
let private_account_1 = AccountWithMetadata {
|
||||||
|
account: Account {
|
||||||
|
program_owner: program.id(),
|
||||||
|
balance: 100,
|
||||||
|
..Account::default()
|
||||||
|
},
|
||||||
|
is_authorized: true,
|
||||||
|
};
|
||||||
|
let private_account_2 = AccountWithMetadata {
|
||||||
|
account: Account::default(),
|
||||||
|
is_authorized: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Setting three private account keys for a circuit execution with only two private
|
||||||
|
// accounts.
|
||||||
|
let private_account_keys = [
|
||||||
|
(
|
||||||
|
sender_keys.npk(),
|
||||||
|
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
recipient_keys.npk(),
|
||||||
|
SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
sender_keys.npk(),
|
||||||
|
SharedSecretKey::new(&[57; 32], &sender_keys.ivk()),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
let result = execute_and_prove(
|
||||||
|
&[private_account_1, private_account_2],
|
||||||
|
&Program::serialize_instruction(10u128).unwrap(),
|
||||||
|
&[1, 2],
|
||||||
|
&[0xdeadbeef1, 0xdeadbeef2],
|
||||||
|
&private_account_keys,
|
||||||
|
&[(sender_keys.nsk, (0, vec![]))],
|
||||||
|
&program,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::CircuitProvingError(_))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_circuit_should_fail_with_too_many_private_account_auth_keys() {
|
||||||
|
let program = Program::simple_balance_transfer();
|
||||||
|
let sender_keys = test_private_account_keys_1();
|
||||||
|
let recipient_keys = test_private_account_keys_2();
|
||||||
|
let private_account_1 = AccountWithMetadata {
|
||||||
|
account: Account {
|
||||||
|
program_owner: program.id(),
|
||||||
|
balance: 100,
|
||||||
|
..Account::default()
|
||||||
|
},
|
||||||
|
is_authorized: true,
|
||||||
|
};
|
||||||
|
let private_account_2 = AccountWithMetadata {
|
||||||
|
account: Account::default(),
|
||||||
|
is_authorized: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Setting two private account keys for a circuit execution with only one non default
|
||||||
|
// private account (visibility mask equal to 1 means that auth keys are expected).
|
||||||
|
let visibility_mask = [1, 2];
|
||||||
|
let private_account_auth = [
|
||||||
|
(sender_keys.nsk, (0, vec![])),
|
||||||
|
(recipient_keys.nsk, (1, vec![])),
|
||||||
|
];
|
||||||
|
let result = execute_and_prove(
|
||||||
|
&[private_account_1, private_account_2],
|
||||||
|
&Program::serialize_instruction(10u128).unwrap(),
|
||||||
|
&visibility_mask,
|
||||||
|
&[0xdeadbeef1, 0xdeadbeef2],
|
||||||
|
&[
|
||||||
|
(
|
||||||
|
sender_keys.npk(),
|
||||||
|
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
recipient_keys.npk(),
|
||||||
|
SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
&private_account_auth,
|
||||||
|
&program,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::CircuitProvingError(_))));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,12 +5,12 @@ type Instruction = ();
|
|||||||
fn main() {
|
fn main() {
|
||||||
let ProgramInput { pre_states, .. } = read_nssa_inputs::<Instruction>();
|
let ProgramInput { pre_states, .. } = read_nssa_inputs::<Instruction>();
|
||||||
|
|
||||||
let [pre1, _] = match pre_states.try_into() {
|
let [pre1, pre2] = match pre_states.try_into() {
|
||||||
Ok(array) => array,
|
Ok(array) => array,
|
||||||
Err(_) => return,
|
Err(_) => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
let account_pre1 = pre1.account.clone();
|
let account_pre1 = pre1.account.clone();
|
||||||
|
|
||||||
write_nssa_outputs(vec![pre1], vec![account_pre1]);
|
write_nssa_outputs(vec![pre1, pre2], vec![account_pre1]);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user