Commit Graph
131 Commits
Author SHA1 Message Date
Artem Gureev 5bf8a0e088 test(lee): pin state purity against event emission 2026-08-22 20:07:18 +00:00
agureev d7a143d26c chore: docs + artifacts 2026-08-22 14:11:14 +00:00
Artem Gureev a32afb2efb test(lee): selector round-trip and private-path emitter coverage 2026-08-22 14:07:39 +00:00
Artem Gureev aab4e5651a feat!(lee): add event selector field
BREAKING!

Before: Program outputs carried and opaque vector of event blobs.

After: Outputs now bear a vector of `ProgramOutputs` struct which also
have selectors attached.

Mitigation: Apply selectors to all event emissions for current programs.
2026-08-22 11:06:17 +00:00
Artem Gureev 4ed6fcc1cd test(lee): use expect in the emitter test helper 2026-08-22 10:23:35 +00:00
Artem Gureev ed0415db87 refactor(lee): use InstructionData for the emitter chain payload 2026-08-22 10:20:29 +00:00
Artem GureevandSergio Chouhy 43a85f8eb0 doc: update lee/state_machine/core/src/program/mod.rs
Co-authored-by: Sergio Chouhy <41742639+schouhy@users.noreply.github.com>
2026-08-22 09:05:11 +00:00
agureev e5d4d87ca6 doc: add privacy event-drop documentation 2026-08-22 09:05:11 +00:00
agureev 87fb34fd34 chore: docs 2026-08-22 09:05:11 +00:00
Artem Gureev 225470c5a2 test(lee): parameterized event-emitter guest and coverage 2026-08-22 08:42:56 +00:00
Artem Gureev a080dce0af feat(lee): thread program events through public validation 2026-08-22 08:41:30 +00:00
Artem Gureev f414aa03c0 feat!(lee): add events to ProgramOutput
BREAKING!

Before: Program output did not contain events.

After: Program outputs contain an extra vector field of events.

Mitigation: migrate the programs to use the updated output struct.
2026-08-22 08:38:19 +00:00
jonesmarvin8 96c8577db8 refactor(lee): fold program storage into public_state (#723)
V03State.programs is gone; deployed programs now live directly in public_state, keyed by AccountId::from(program_id) same as any other account. insert_program sets program_owner to a new reserved sentinel, PROGRAM_STORAGE_OWNER, instead of leaving it at the default.

That ownership choice is load-bearing now in a way it wasn't before: once program accounts share the same map as everything else, they're reachable through ordinary dispatch, so program_owner determines whether they're claimable/writable. Left unclaimed, a program invocation could legitimately claim a program's storage account via the normal claim path and then rewrite its elf; self-ownership has the same flaw, since it authorizes exactly the program whose own invocation would touch its own storage account. The reserved sentinel makes every program account unwritable by construction, since no real chained_call.program_id will ever derive to it.

Also centralizes the program-ownership check behind V03State::get_program and applies the program_owner AccountId migration to code added after the earlier rebase.
2026-08-18 12:44:06 -04:00
jonesmarvin8andClaude Sonnet 5 2ba1ecd609 refactor!(lee): Change program_owner: ProgramId to AccountId (#722)
* feat(lee): store deployed programs as Account-shaped state, keyed by AccountId

Program-as-Account migration, first slice: V03State.programs becomes
HashMap<AccountId, Account> instead of HashMap<ProgramId, Program>,
with the elf held directly in Account.data. The map key is derived
from ProgramId via a new 1:1 From<ProgramId> for AccountId conversion
(both types are exactly 32 bytes) rather than a hash, since ProgramId
is already content-derived from the elf.

Account.program_owner stays ProgramId-typed everywhere - this only
changes how deployed programs are stored and looked up host-side, not
the dispatch/authorization model any guest program logic depends on.
Dispatch resolves a ChainedCall's program_id by converting to
AccountId, fetching the Account, and reconstructing a Program via
new_unchecked for execution.

DATA_MAX_LENGTH is raised from 100 KiB to 700 KiB to fit real program
elfs (observed 375 KB-631 KB) directly in Account.data; noted in its
docstring as a rough placeholder pending real transaction/block-size
budget analysis.

* fix(lee): store deployed programs as Account-shaped state, correct SeenShard cap

Corrects lee/state_machine internals for the Program-as-Account migration
and fixes SeenShard::MAX_DELIVERIES, which was still calibrated for the
old 100 KiB DATA_MAX_LENGTH instead of the current 700 KiB cap. Rebuilds
program artifacts and the sequencer test fixture to match.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* address PR #720 review nits

- Use FIXME instead of TODO for the temporary ProgramId->AccountId
  conversion, per review convention for patches guaranteed to be
  fixed later.
- Derive cross_zone_inbox's MAX_DELIVERIES from DATA_MAX_LENGTH
  instead of a hand-recomputed literal, so it stays in sync
  automatically the next time the cap changes.

* feat(lee): migrate Account.program_owner from ProgramId to AccountId

Account.program_owner is now AccountId-typed instead of ProgramId,
via a new bijective From<ProgramId> for AccountId / From<AccountId>
for ProgramId conversion pair (pure byte reinterpretation, not a
hash - both types are exactly 32 bytes). Adds DEFAULT_PROGRAM_OWNER
as the AccountId-typed counterpart to DEFAULT_PROGRAM_ID, used at
every program_owner comparison/claim site instead of an inline
AccountId::default().

Touches every call site across lee_core, lee (including the
guest-side privacy-preserving circuit), all 16 deployed guest
programs, wallet/wallet-ffi, indexer_ffi/indexer_service/
indexer_service_protocol, sequencer_core, testnet_initial_state,
system_accounts, cross_zone, storage, cycle_bench, and
integration_tests - mostly mechanical .into() conversions, plus two
simplifications: wallet's manual base58 encode/decode of
program_owner was dead code once it's AccountId (which already has
Display/FromStr), and the FFI crates' program_owner field now reuses
the existing generic FfiBytes32 wrapper instead of the now-unused
FfiProgramId one.

Rebuilds every guest ELF artifact and the prebuilt sequencer test
fixture via just build-artifacts, since execute_and_prove runs
against the checked-in precompiled privacy_preserving_circuit.bin,
which isn't rebuilt automatically by cargo test/check.

* chore(lee): rebuild artifacts after rebase, drop unused base58 dep

Rebases marvin/program-as-account-2 onto the updated
marvin/program-as-account (SeenShard cap fix), regenerating program
and circuit artifacts plus the sequencer test fixture to match.
Also removes lez/wallet's now-unused base58 dependency, dead since
AccountId gained its own Display/FromStr base58 encoding.

* docs(lee): trim DEFAULT_PROGRAM_OWNER and From<AccountId> for ProgramId docs

* test(lee): add known-answer tests for ProgramId/AccountId conversion, rebuild artifacts

* fix(lee): apply program_owner AccountId migration to code added after rebase

dev grew new program_owner call sites (sequencer_stake genesis/config
handling, committee_discovery, a new selective_pda_delegator test
program, and related tests) after this branch's ProgramId->AccountId
migration commit was originally written, so they predated the .into()
sweep and didn't conflict during the rebase - they just still assumed
the old ProgramId-typed field. Converts all of them, fixes a stray
unseparated hex literal clippy caught along the way, and rebuilds
artifacts against the fixed source.

* chore(lee): regenerate test fixture after rebasing onto dev

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-18 11:26:57 -04:00
jonesmarvin8andClaude Sonnet 5 d52c76e2b5 refactor(lee): change programs shape (#720)
* feat(lee): store deployed programs as Account-shaped state, keyed by AccountId

Program-as-Account migration, first slice: V03State.programs becomes
HashMap<AccountId, Account> instead of HashMap<ProgramId, Program>,
with the elf held directly in Account.data. The map key is derived
from ProgramId via a new 1:1 From<ProgramId> for AccountId conversion
(both types are exactly 32 bytes) rather than a hash, since ProgramId
is already content-derived from the elf.

Account.program_owner stays ProgramId-typed everywhere - this only
changes how deployed programs are stored and looked up host-side, not
the dispatch/authorization model any guest program logic depends on.
Dispatch resolves a ChainedCall's program_id by converting to
AccountId, fetching the Account, and reconstructing a Program via
new_unchecked for execution.

DATA_MAX_LENGTH is raised from 100 KiB to 700 KiB to fit real program
elfs (observed 375 KB-631 KB) directly in Account.data; noted in its
docstring as a rough placeholder pending real transaction/block-size
budget analysis.

* fix(lee): store deployed programs as Account-shaped state, correct SeenShard cap

Corrects lee/state_machine internals for the Program-as-Account migration
and fixes SeenShard::MAX_DELIVERIES, which was still calibrated for the
old 100 KiB DATA_MAX_LENGTH instead of the current 700 KiB cap. Rebuilds
program artifacts and the sequencer test fixture to match.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* address PR #720 review nits

- Use FIXME instead of TODO for the temporary ProgramId->AccountId
  conversion, per review convention for patches guaranteed to be
  fixed later.
- Derive cross_zone_inbox's MAX_DELIVERIES from DATA_MAX_LENGTH
  instead of a hand-recomputed literal, so it stays in sync
  automatically the next time the cap changes.

* chore: regenerate artifacts after rebasing onto dev

Binary program artifacts and the prebuilt sequencer DB dump were left
as rebase-conflict placeholders; regenerated via `just build-artifacts`
against the fully rebased source.

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-18 10:06:42 -04:00
Artem Gureev f83cf9b300 perf(lee): extend the caller set for the child authorization scope 2026-08-17 17:29:56 +00:00
Artem Gureev 49a8d00260 doc: correct globally_authorized scope description 2026-08-17 17:29:56 +00:00
Artem Gureev 05c72e2863 doc: fix stale function name in comment 2026-08-17 17:29:56 +00:00
Artem Gureev f707d5e8fb refactor(lee): dedup test, function naming 2026-08-17 17:23:39 +00:00
Artem Gureev f828026df9 fix(lee): authorize caller-seeded public PDAs at first sight 2026-08-17 17:23:39 +00:00
agureev c77313b5ca fix(lee): check private PDA authorization on first sight 2026-08-17 17:23:39 +00:00
agureev 79c43dc5a0 fix!(lee): scope private PDA authorization to the callee subtree
BREAKING!

Before: authorized private PDAs remain authorized for the rest of the
calls after.

After: the authorized preivate PDAs remain authorized for the rest of
the callee subtree.
2026-08-17 17:23:39 +00:00
jonesmarvin8andClaude Sonnet 5 2a7a586a59 refactor(key-protocol)!: introduce constitent domain separators for key protocol (#717)
* feat(key_protocol): version-independent domain separators for normal keys

Introduce a /LEE-Keys/v1/... namespace for account key derivation
(private and public), distinct from LEE protocol versioning
(/LEE/v0.3/...). This lets the key derivation protocol evolve
independently of the transaction/message format version, so a LEE
version bump doesn't silently rotate or orphan user keys.

Covers master/child private and public key derivation, authorization
and viewing secret keys, and nullifier secret/public key derivation
(the latter also used by the privacy-preserving guest circuit).
Pinned regression tests updated to match the new derivation outputs.

* chore(artifacts): rebuild guest ELFs and test fixture for key protocol change

Regenerated via just build-artifacts after the /LEE-Keys/v1/... domain
separator migration touched lee_core::nullifier, which every guest
program links against, and changed derived account IDs embedded in
the prebuilt sequencer fixture.

* test(testnet_initial_state): update pinned private-account values for new key domain separators

initial_priv_accounts_private_keys() derives from fixed SSK roots
through the key_protocol chain the /LEE-Keys/v1/... migration changed,
so the derived viewing secret keys and account addresses shifted even
though the SSK roots themselves didn't. Public account addresses are
unaffected since they sign with a raw PrivateKey outside this chain.

* chore(artifacts): rebuild guest ELFs and test fixture after dev rebase

The rebase onto dev conflicted on these binaries (dev had independently
rebuilt them since this branch diverged). Conflicts were resolved
provisionally during the rebase and are now replaced with a fresh
build-artifacts run against the fully merged tree.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-17 10:08:12 -04:00
Sergio Chouhy b1eb69322c fix(integration_tests): multi sequencer now builds the state with two accredited keys from channel creation 2026-08-13 18:47:50 -03:00
agureev 1f7a4c4162 doc: fix typo 2026-08-10 12:32:57 +04:00
Artem Gureev 5a1524dcb9 refactor(lee): update stale domain for keytree parent 2026-08-07 17:13:41 +04:00
Artem Gureev 279a9b8313 feat!(lee): derive private authorization from an authorization secret key
BREAKING!

Before: Providing `nsk` was the same as authorizing a regular private
account.

After: A separate `ask` is required, making unauthorized private
updates possible.
2026-08-07 10:41:56 +00:00
Artem Gureev fc8f7f2d42 refactor(lee): verbose key domains and the ask key chain 2026-08-07 10:40:04 +00:00
Artem Gureev ca23f12f7a refactor(lee): keep the authorization precondition match wildcard-free 2026-08-05 11:43:02 +04:00
agureev d05035eb9e refactor(lee): refactor private kinds 2026-08-04 15:55:09 +04:00
agureev ccb426960f Merge remote-tracking branch 'origin/dev' into artem/bundle-actions 2026-08-04 14:21:00 +04:00
Roman 54743142e9 test: bridge guard account flags modification 2026-07-31 17:56:00 -03:00
agureev 0e957b5c08 chore: docs for PrivateAction commitment field 2026-07-31 00:47:04 +04:00
agureev dbcdbb29f3 Merge remote-tracking branch 'origin/dev' into artem/bundle-actions 2026-07-31 00:16:31 +04:00
erhant 0659774e43 chore(state_machine); rename get_public_account to get_account_by_id_ref [skip ci] 2026-07-30 14:23:49 +03:00
erhant 57759d8953 fix(bridge): enforce deposit exactly-once via a per-op-id receipt PDA 2026-07-30 14:21:10 +03:00
Artem Gureev 75326d031a refactor(verifier): consume bundled public_actions directly 2026-07-29 18:18:08 +00:00
Artem Gureev f16c3bd1e2 refactor: bundle private/public i/o into action struccts 2026-07-29 18:16:13 +00:00
Artem Gureev 7a80ab026d refactor!(lee_core): bump the note-encryption KDF domain to v0.3
BREAKING!

Before: note encryption KDF used 0.2 tag

After: now uses 0.3 tag

Mitigation: cipher keygen needs to utilize 0.3 tag after this commit
2026-07-28 16:13:14 +04:00
Artem Gureev 626ba01449 test: order-independent output assertions + wrong-nullifier decrypt 2026-07-28 11:13:19 +00:00
Artem Gureev 590ad2b53c test(circuit): assert obfuscate_output_ordering sorts and keeps notes paired 2026-07-28 11:12:21 +00:00
Artem Gureev e282ef30e1 refactor(circuit): extract obfuscate_output_ordering 2026-07-28 11:10:23 +00:00
Artem Gureev 29ee254322 feat!: byte-sort private outputs to obfuscate note order
BREAKING!

Before: Commitments, nullifier, and ciphertexts of a transaction were
position-aligned. The position revealed which nullifier was hiding a
pre-state to a commitment to which post-state. Similarly with
ciphertexts.

After: The nullifier-cipher connection remains, but now they (and
commitments independently) are shuffled by the byte-order of the
hashes.

Mitigation: Expect the circuit outputs to be jumbled.
2026-07-28 11:09:44 +00:00
Artem Gureev e13b4cb237 feat!: key note encryption on the nullifier, drop the output index
BREAKING!

Before: The ciphertext key got generated via using the commmitment and
its index as the key.

After: The ciphertext key replaces the commitment dependence by a
nullifier dependence, still making the key unique by global state. The
nullifier is assumed to be the nullifier of the pre-state of the account.

Mitigation: Use the new decryption algorithm.
2026-07-28 11:09:28 +00:00
Artem Gureev a9f492bb3f refactor(lee_core): expose nullifier byte-array 2026-07-28 10:58:57 +00:00
Artem Gureev 2e8a01ac95 refactor: warn on private-padding saturation and rename to execute_and_prove_with_padded_inputs 2026-07-24 17:00:36 +00:00
Artem Gureev 2999288a57 test(lee): pin for_dummy nullifier and commitment derivations 2026-07-24 16:38:04 +00:00
Artem Gureev d30490442d fix(wallet): encapsulate dummy note epk in wallet 2026-07-24 16:37:52 +00:00
Artem Gureev 4ba0268bab feat(wallet): construct and submit dummy inputs
Ciphers submitted currently have no data
2026-07-24 16:36:13 +00:00
Artem Gureev 5d13e0acc5 feat(circuit): use dummy_inputs in ppc 2026-07-24 16:36:13 +00:00