103 Commits

Author SHA1 Message Date
Moudy
8a8bac8b69 ci: address fmt-rs, lint, and unit-tests failures from the merge 2026-04-30 22:16:26 +02:00
Moudy
8517906025 Merge branch 'main' into moudy/feat-strong-type-circuit-input 2026-04-30 20:17:47 +02:00
Moudy
98da9b26cc fix: address PR review feedback
- Rename PrivacyPreservingCircuitInputAccount to InputAccountIdentity (drop the PrivacyPreservingCircuit prefix; add Identity suffix)
- Rename PrivacyPreservingCircuitInput.accounts to account_identities
- Rename AccountManager.accounts() to account_identities() and loop variables to account_identity
- Drop legacy mask-1/2/3 references from variant doc comments and guest comments
- Remove the explanatory comments about deleted parallel-vec tests; moved to the PR description
- Rebake privacy_preserving_circuit and test program artifacts
2026-04-30 15:46:36 +02:00
Moudy
55a4a1d83b ci: fix fmt-rs, deny advisory, and rebake artifacts 2026-04-29 08:54:19 +02:00
Moudy
f7349656c7 refactor: strong-type PrivacyPreservingCircuitInput with per-account enum 2026-04-29 07:37:30 +02:00
Sergio Chouhy
924b30650c change pda reserved identifier 2026-04-27 18:45:19 -03:00
Sergio Chouhy
e09cb6284e enforce reserved identifier for private pda 2026-04-24 18:00:54 -03:00
Sergio Chouhy
52992a124a fix identifier for pda 2026-04-24 17:04:40 -03:00
Sergio Chouhy
7c45b5af3c Merge branch 'main' into schouhy/generalize-npk-to-multiple-accounts 2026-04-24 01:04:55 -03:00
Moudy
e5b77a27d5 refactor: localize private_pda_npk_by_position and extract authorization helper
Addresses the following review comments from @Arjentix:

- "I think we can move this into `derive_from_outputs()`"
  (on the position → npk map construction in main())
  I moved the construction inside ExecutionState::derive_from_outputs
  and stored the map as a field of ExecutionState. derive_from_outputs
  now takes `private_account_keys` directly and builds the map as part
  of state initialization. main() no longer owns the intermediate
  structure. validate_and_sync_states reads the npk through
  self.private_pda_npk_by_position.

- "Let's move this whole `is_authorized` computation into a separate
  function. This became really bulky"
  I extracted the caller-seeds resolution, family-binding recording,
  and is_authorized computation into a free function
  `resolve_authorization_and_record_bindings`. It takes the three
  field borrows it needs (`&mut pda_family_binding`, `&mut
  private_pda_bound_positions`, `&private_pda_npk_by_position`), same
  shape as `assert_family_binding`. A method would have conflicted
  with the `&mut self.post_states` borrow held by the Occupied match
  arm; the free function lets rustc split-borrow the self fields.
2026-04-22 15:55:35 +02:00
Sergio Chouhy
670527c2f1 Merge branch 'main' into schouhy/generalize-npk-to-multiple-accounts 2026-04-21 18:53:24 -03:00
Moudy
0183eac5cc refactor: unify PDA AccountId construction via AccountId::for_{public,private}_pda
Addresses the following review comment:

- "I think this should be a constructor `AccountId::for_private_pda`.
  Consider also removing the existing `impl From<(ProgramId, Seed)> for
  AccountId` for public pdas in favor of a `AccountId::for_public_pda`
  to have a unified way of constructing pdas"

I replaced `impl From<(&ProgramId, &PdaSeed)> for AccountId` with
`AccountId::for_public_pda(program_id: &ProgramId, seed: &PdaSeed) ->
Self` and replaced the free function `private_pda_account_id(...)`
with `AccountId::for_private_pda(program_id: &ProgramId, seed:
&PdaSeed, npk: &NullifierPublicKey) -> Self`. Both live in an inherent
`impl AccountId` block in nssa/core/src/program.rs next to the PDA
derivation logic. Migrated all call sites across nssa/core,
nssa/src/state.rs, nssa/src/validated_state_diff.rs,
program_methods/guest/src/bin/privacy_preserving_circuit.rs,
programs/amm/core, programs/associated_token_account/core, the example
tail-call binary, and the ATA tutorial doc. Test function names that
referenced the old free function were also renamed
(private_pda_account_id_* to for_private_pda_*).
2026-04-21 12:35:19 +02:00
Moudy
68d43d7f2b 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.
2026-04-21 02:08:02 +02:00
Moudy
e8b17eef27 refactor: rename mask3 to private_pda in tests and circuit
Addresses the following review comments:

- "I'd rename all mask_3 references in test names and variables to a
  private pda wording. If in the future we change the mask number for
  the private pda, this naming will silently get outdated."
  I renamed all tests and the local variable mask3_account to
  private_pda_account.

- "Let's use more descriptive names. `mask3` is not very meaningful."
  I renamed all `mask3` into `private_pda`. Panic messages and .expect
  strings updated to match. Doc comments that factually describe the
  encoding (e.g. "mask-3 account" meaning "an account whose visibility
  mask is 3") are left as-is since they are accurate and remain stable
  until the mask value itself changes.

- "..._panics" to "..._fails"
  Covered above. The tests assert Err(CircuitProvingError), so
  execute_and_prove returns an Err, the test process itself never
  panics.

- "we can return `Some((*seed, true, caller))` to avoid having to unwrap
  the `caller_program_id` again in line 290"
  I changed matched_caller_seed from Option<(PdaSeed, bool)> to
  Option<(PdaSeed, bool, ProgramId)>, return the `caller` captured by
  the enclosing and_then from each match arm, and dropped the .expect
  at the consumer site. Bundled with the rename since both touch the
  same branch and a single guest ELF rebuild covers them.
2026-04-21 01:43:57 +02:00
Moudy
00cae12d41 docs: drop "wallet" references from nssa crate
Addresses the following review comments:

- "I'd keep this crate independent of wallet references"
  I replaced all with "supplied npk".

- Rename request on locals attested_keys/wallet_keys
  In mask_3_wallet_npk_mismatch_panics the two key sets play distinct
  roles, one produces the pre_state's account_id (the registered pair)
  and the other is supplied in private_account_keys as the mismatched
  npk. Collapsing both to `keys` would be misleading. I renamed to
  keys_a and keys_b with an inline comment noting which one is the
  registered one and which one is mismatched.
2026-04-21 01:02:22 +02:00
Moudy
34f8b6cac8 docs: split miscoupled private-PDA test docs and clean phrasing
Addresses the following review comments:

- "Isn't two_mask_3_claims_under_same_seed_are_rejected already checking
  that there's a mechanism protecting against this exploit scenario?"
  The doc block at nssa/src/state.rs:2488-2504 mixes three paragraphs,
  one about reuse, one TODO about wallet side input, one exploit pin,
  all attached to two_mask_3_claims_under_same_seed_are_rejected. The
  reuse test below it had no doc at all. I split as follows: the
  exploit-pin paragraph stays on two_mask_3_claims_..., the reuse
  paragraph moves to a fresh docstring on
  mask_3_reuse_across_txs_currently_unsupported.

- "I don't understand this. I think this should fail because ... the
  input pre_state which is marked with is_authorized=true will make
  things fail."
  The reuse test's new docstring cites the actual reject site, the
  post-loop private_pda_bound_positions assertion in
  privacy_preserving_circuit.rs:185-192. At top level the Entry::Vacant
  arm accepts is_authorized=true unconditionally, the rejection comes
  from the bound-positions check firing because noop emits no Claim::Pda
  and there is no caller ChainedCall.pda_seeds.

- "let's dont have this TODO as part of the doc"
  The block is moved out into regular // comments immediately above
  mask_3_reuse_across_txs_currently_unsupported.

- "let's not add implementation details to docs"
  In caller_pda_seeds_authorize_mask_3_private_pda_for_callee's
  docstring, I dropped the parenthetical "(Occupied branch)" and the
  trailing sentence about which validate_and_sync_states code path gets
  exercised.

- "what does \`Claim::Pda(seed)\` / \`pda_seeds\` mean?"
  I rewrote the pda_family_binding docstring at
  privacy_preserving_circuit.rs:33-39: replaced the ambiguous
  "Claim::PrivatePda and ChainedCall's private seeds into plain
  Claim::Pda(seed) / pda_seeds" phrase with "a Claim::Pda(seed) in a
  program's post_state or a caller's ChainedCall.pda_seeds entry".

- Suggestion on nssa/src/validated_state_diff.rs:226 rewriting
  "The public-execution path only sees mask-0 accounts" to
  "The public-execution path only sees public accounts".
  Applied: "The public-execution path only sees public accounts".

- Clarification requested on the private_pda_bound_positions field:
  I expanded the docstring at privacy_preserving_circuit.rs:26-31 to
  state that binding is an idempotent property, not an event, and to
  enumerate the two proof paths that populate it (a Claim::Pda on a
  mask-3 pre_state, or a caller's pda_seeds matching under the private
  derivation).
2026-04-21 00:37:06 +02:00
Sergio Chouhy
6316f59777 fmt 2026-04-19 23:13:51 -03:00
Sergio Chouhy
c30d435155 update nonce init formula to depend on account id instead of just npk 2026-04-19 19:28:10 -03:00
Moudy
d3577f02bc fix: reject multiple family members under same (program, seed) in one tx 2026-04-17 15:36:20 +02:00
Moudy
f9a5a7635e refactor: make programs privacy-agnostic in the privacy circuit 2026-04-17 07:29:40 +02:00
Sergio Chouhy
3cf7972425 add identifier to ciphertext and use it on sync mechanism 2026-04-16 23:22:40 -03:00
Moudy
4b09aae852 fix: doc backticks and rebuild artifacts 2026-04-16 19:26:27 +02:00
Moudy
93c6921eaf Merge remote-tracking branch 'origin/main' into moudy/feat-private-pdas
# Conflicts:
#	artifacts/program_methods/amm.bin
#	artifacts/program_methods/associated_token_account.bin
#	artifacts/program_methods/authenticated_transfer.bin
#	artifacts/program_methods/clock.bin
#	artifacts/program_methods/pinata.bin
#	artifacts/program_methods/pinata_token.bin
#	artifacts/program_methods/privacy_preserving_circuit.bin
#	artifacts/program_methods/token.bin
#	artifacts/test_program_methods/burner.bin
#	artifacts/test_program_methods/chain_caller.bin
#	artifacts/test_program_methods/changer_claimer.bin
#	artifacts/test_program_methods/claimer.bin
#	artifacts/test_program_methods/clock_chain_caller.bin
#	artifacts/test_program_methods/data_changer.bin
#	artifacts/test_program_methods/extra_output.bin
#	artifacts/test_program_methods/flash_swap_callback.bin
#	artifacts/test_program_methods/flash_swap_initiator.bin
#	artifacts/test_program_methods/malicious_authorization_changer.bin
#	artifacts/test_program_methods/malicious_caller_program_id.bin
#	artifacts/test_program_methods/malicious_self_program_id.bin
#	artifacts/test_program_methods/minter.bin
#	artifacts/test_program_methods/missing_output.bin
#	artifacts/test_program_methods/modified_transfer.bin
#	artifacts/test_program_methods/nonce_changer.bin
#	artifacts/test_program_methods/noop.bin
#	artifacts/test_program_methods/pinata_cooldown.bin
#	artifacts/test_program_methods/program_owner_changer.bin
#	artifacts/test_program_methods/simple_balance_transfer.bin
#	artifacts/test_program_methods/time_locked_transfer.bin
#	artifacts/test_program_methods/validity_window.bin
#	artifacts/test_program_methods/validity_window_chain_caller.bin
#	nssa/core/src/program.rs
#	nssa/src/state.rs
2026-04-16 18:25:57 +02:00
Moudy
bda21fb5c5 refactor: move private PDA npk into proven ChainedCall and Claim 2026-04-16 16:53:54 +02:00
Moudy
b1553109ae fix: validate no duplicate entries in private_pda_info 2026-04-16 00:01:25 +02:00
Moudy
b0c10ee5a2 fix: cargo fmt, add #[must_use] to private_pda_account_id, rebuild artifacts 2026-04-15 21:10:22 +02:00
Moudy
cee9608ea7 feat: enable PDA claim verification for private PDA accounts 2026-04-15 21:10:21 +02:00
Moudy
308e1ebebf feat: add mask 3 branch in compute_circuit_output for private PDAs 2026-04-15 21:10:21 +02:00
Moudy
10b26ca223 feat: thread private_pda_info through the privacy circuit and extend compute_authorized_pdas 2026-04-15 21:10:21 +02:00
Sergio Chouhy
a4af8da13b replace npk for account id in commitment and init nullifier formulas 2026-04-14 23:45:34 -03:00
Sergio Chouhy
dae617c673 wip: add dummy identifier 2026-04-14 18:02:38 -03:00
Daniil Polyakov
699e91363e feat: introduce more descriptive error messages for public execution 2026-04-13 21:25:18 +03:00
Moudy
a87e8d93dc fix: cargo fmt 2026-04-07 20:16:42 +02:00
Moudy
56ee93b5b7 merge main into feat-caller-program-id-and-flash-swap 2026-04-07 19:44:55 +02:00
Moudy
b22a989fbc merge main into feat-caller-program-id-and-flash-swap 2026-04-07 19:27:27 +02:00
Moudy
7d465dded7 fix: verify caller_program_id in program output 2026-04-07 19:03:06 +02:00
Sergio Chouhy
deae71b09f handle comments 2026-04-03 18:13:24 -03:00
Moudy
74e16db68f fix: apply formatting and rebuild artifacts 2026-04-03 01:17:42 +02:00
moudyellaz
087baebcca feat: add caller_program_id to ProgramInput 2026-04-03 00:58:11 +02:00
Sergio Chouhy
4d5010f044 Merge branch 'main' into schouhy/add-block-context-system-accounts 2026-04-02 19:48:55 -03:00
Sergio Chouhy
6a467da3b1 fmt and clippy 2026-04-02 17:48:02 -03:00
Moudy
531381e023 Update program_methods/guest/src/bin/privacy_preserving_circuit.rs
Co-authored-by: Daniil Polyakov <arjentix@gmail.com>
2026-04-02 20:30:52 +02:00
Moudy
702ef4a46f fix: cargo fmt 2026-04-02 20:30:27 +02:00
moudyellaz
58b72dd77c refactor: pass self_program_id to ProgramOutput in production guest programs 2026-04-02 20:30:16 +02:00
moudyellaz
85cc323649 feat: verify self_program_id in privacy circuit 2026-04-02 20:30:16 +02:00
Moudy
59d3d38448 fix: serialize write_inputs fields separately to match guest deserialization 2026-04-02 20:29:12 +02:00
moudyellaz
9ecf186851 refactor: update all guest programs to handle self_program_id field 2026-04-02 20:29:10 +02:00
Andrea Franz
7d75eb2d59 chore(programs/amm): rename Swap to SwapExactInput 2026-04-02 16:10:12 +02:00
Andrea Franz
9a6ec0018b feat(programs/amm): add swap exact output functionality 2026-04-02 16:10:12 +02:00
Sergio Chouhy
fa2fd857a9 minor refactor 2026-04-01 00:01:11 -03:00