mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-05-12 04:40:04 +00:00
test: exercise callee authorization in private-PDA delegation tests
Addresses the following review comments:
- "Shouldn't we use a program that checks authorization in this test as
callee? If not, I'm not sure if we are fully testing what the test
docs describe (namely, that the callee got the input account with
is_authorized=true). Maybe add a variant of the noop that checks the
input account is authorized."
I added test_program_methods/guest/src/bin/auth_asserting_noop.rs:
same shape as noop.rs except it asserts pre.is_authorized == true for
every pre_state before echoing the post_states. Any unauthorized
pre_state panics the guest, failing the whole circuit proof. I added
Program::auth_asserting_noop() as the matching helper. In
caller_pda_seeds_authorize_private_pda_for_callee and
caller_pda_seeds_with_wrong_seed_rejects_private_pda_for_callee, I
swapped Program::noop() for Program::auth_asserting_noop() as the
callee. The positive test now proves the callee actually sees
is_authorized=true, not just that the circuit's consistency check did
not reject. The negative test doubles its evidence, both the
circuit's authorization reconciliation and the callee guest would now
reject a wrong-seed delegation.
- "This branching logic is only correct because we are not supporting
non-authorized private accounts with non-default values. Likely to be
changed in the future. I'm sure there's use cases for this. For
example the multisig program if ran completely private it would need
a private non-default and non-authorized input account."
Agreed. Supporting this needs wallet-supplied `(seed, owner)` side
input so the npk-to-account_id binding can be re-verified for an
existing private PDA without a fresh Claim::Pda or a caller
pda_seeds match. I handled this in the second PR. I added a
TODO(private-pdas-pr-2/3) marker on the `else` branch in
privacy_preserving_circuit.rs:3 => { ... } so the constraint is
visible to future maintainers, along with a comment noting the
multisig use case.
This commit is contained in:
parent
d22c142a37
commit
68d43d7f2b
Binary file not shown.
BIN
artifacts/test_program_methods/auth_asserting_noop.bin
Normal file
BIN
artifacts/test_program_methods/auth_asserting_noop.bin
Normal file
Binary file not shown.
@ -342,6 +342,16 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn auth_asserting_noop() -> Self {
|
||||
use test_program_methods::{AUTH_ASSERTING_NOOP_ELF, AUTH_ASSERTING_NOOP_ID};
|
||||
|
||||
Self {
|
||||
id: AUTH_ASSERTING_NOOP_ID,
|
||||
elf: AUTH_ASSERTING_NOOP_ELF.to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn malicious_authorization_changer() -> Self {
|
||||
use test_program_methods::{
|
||||
|
||||
@ -2425,7 +2425,7 @@ pub mod tests {
|
||||
#[test]
|
||||
fn caller_pda_seeds_authorize_private_pda_for_callee() {
|
||||
let delegator = Program::private_pda_delegator();
|
||||
let noop = Program::noop();
|
||||
let callee = Program::auth_asserting_noop();
|
||||
let keys = test_private_account_keys_1();
|
||||
let npk = keys.npk();
|
||||
let seed = PdaSeed::new([77; 32]);
|
||||
@ -2434,12 +2434,13 @@ pub mod tests {
|
||||
let account_id = private_pda_account_id(&delegator.id(), &seed, &npk);
|
||||
let pre_state = AccountWithMetadata::new(Account::default(), false, account_id);
|
||||
|
||||
let noop_id = noop.id();
|
||||
let program_with_deps = ProgramWithDependencies::new(delegator, [(noop_id, noop)].into());
|
||||
let callee_id = callee.id();
|
||||
let program_with_deps =
|
||||
ProgramWithDependencies::new(delegator, [(callee_id, callee)].into());
|
||||
|
||||
let result = execute_and_prove(
|
||||
vec![pre_state],
|
||||
Program::serialize_instruction((seed, seed, noop_id)).unwrap(),
|
||||
Program::serialize_instruction((seed, seed, callee_id)).unwrap(),
|
||||
vec![3],
|
||||
vec![(npk, shared_secret)],
|
||||
vec![],
|
||||
@ -2460,7 +2461,7 @@ pub mod tests {
|
||||
#[test]
|
||||
fn caller_pda_seeds_with_wrong_seed_rejects_private_pda_for_callee() {
|
||||
let delegator = Program::private_pda_delegator();
|
||||
let noop = Program::noop();
|
||||
let callee = Program::auth_asserting_noop();
|
||||
let keys = test_private_account_keys_1();
|
||||
let npk = keys.npk();
|
||||
let claim_seed = PdaSeed::new([77; 32]);
|
||||
@ -2470,12 +2471,13 @@ pub mod tests {
|
||||
let account_id = private_pda_account_id(&delegator.id(), &claim_seed, &npk);
|
||||
let pre_state = AccountWithMetadata::new(Account::default(), false, account_id);
|
||||
|
||||
let noop_id = noop.id();
|
||||
let program_with_deps = ProgramWithDependencies::new(delegator, [(noop_id, noop)].into());
|
||||
let callee_id = callee.id();
|
||||
let program_with_deps =
|
||||
ProgramWithDependencies::new(delegator, [(callee_id, callee)].into());
|
||||
|
||||
let result = execute_and_prove(
|
||||
vec![pre_state],
|
||||
Program::serialize_instruction((claim_seed, wrong_delegated_seed, noop_id)).unwrap(),
|
||||
Program::serialize_instruction((claim_seed, wrong_delegated_seed, callee_id)).unwrap(),
|
||||
vec![3],
|
||||
vec![(npk, shared_secret)],
|
||||
vec![],
|
||||
|
||||
@ -608,7 +608,13 @@ fn compute_circuit_output(
|
||||
let new_nonce = pre_state.account.nonce.private_account_nonce_increment(nsk);
|
||||
(new_nullifier, new_nonce)
|
||||
} else {
|
||||
// New private PDA (like mask 2)
|
||||
// New private PDA (like mask 2). The default + unauthorized requirement
|
||||
// here rules out use cases like a fully-private multisig, which would need
|
||||
// a non-default, non-authorized private PDA input account.
|
||||
// TODO(private-pdas-pr-2/3): relax this once the wallet can supply a
|
||||
// `(seed, owner)` side input so the npk-to-account_id binding can be
|
||||
// re-verified for an existing private PDA without a `Claim::Pda` or caller
|
||||
// `pda_seeds` match.
|
||||
assert_eq!(
|
||||
pre_state.account,
|
||||
Account::default(),
|
||||
|
||||
40
test_program_methods/guest/src/bin/auth_asserting_noop.rs
Normal file
40
test_program_methods/guest/src/bin/auth_asserting_noop.rs
Normal file
@ -0,0 +1,40 @@
|
||||
use nssa_core::program::{AccountPostState, ProgramInput, ProgramOutput, read_nssa_inputs};
|
||||
|
||||
/// A variant of `noop` that asserts every `pre_state.is_authorized == true` before echoing
|
||||
/// the `post_states`. Any unauthorized `pre_state` panics the guest, failing the whole
|
||||
/// circuit proof. Used as a callee in private-PDA delegation tests to actually exercise the
|
||||
/// authorization propagated through `ChainedCall.pda_seeds`.
|
||||
type Instruction = ();
|
||||
|
||||
fn main() {
|
||||
let (
|
||||
ProgramInput {
|
||||
self_program_id,
|
||||
caller_program_id,
|
||||
pre_states,
|
||||
..
|
||||
},
|
||||
instruction_words,
|
||||
) = read_nssa_inputs::<Instruction>();
|
||||
|
||||
for pre in &pre_states {
|
||||
assert!(
|
||||
pre.is_authorized,
|
||||
"auth_asserting_noop: pre_state {} is not authorized",
|
||||
pre.account_id
|
||||
);
|
||||
}
|
||||
|
||||
let post_states = pre_states
|
||||
.iter()
|
||||
.map(|account| AccountPostState::new(account.account.clone()))
|
||||
.collect();
|
||||
ProgramOutput::new(
|
||||
self_program_id,
|
||||
caller_program_id,
|
||||
instruction_words,
|
||||
pre_states,
|
||||
post_states,
|
||||
)
|
||||
.write();
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user