Commit Graph
68 Commits
Author SHA1 Message Date
Marvin Jones f5304fb196 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.
2026-08-22 19:27:13 -04:00
Marvin Jones 6b1f016aee fix(lee): address PR #733 review comments
- RESERVED_DEPLOYMENT_PROGRAM_ACCOUNT_ID: restore the SHA256 derivation
  docstring that explains the constant instead of leaving it as an opaque
  byte array, and switch the array itself to a hex literal (hex-literal,
  already a workspace dependency) for readability.
- Rename the loader/loader_core crate to program_loader/program_loader_core
  to disambiguate it, across the directory, package name, workspace
  members/dependency alias, both dependent crates, and every call site.
2026-08-22 17:39:23 -04:00
Marvin JonesandClaude Sonnet 5 96f2bc1be0 docs(lee): trim redundant doc comments across program-as-account changes
Removed explanatory comments that restated context better left to commit
history/PR description across the deploy-dispatch and program-storage code.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-22 17:39:23 -04:00
Marvin Jones dcc0c4b950 feat(lee): add loader program with native Deploy dispatch fast-path
Introduces a new loader_program/loader_core crate pair implementing a
Deploy instruction that claims a program's ProgramData PDA account
(image_id, segment_number, update_auth, elf_segment), unifying
deployment with ordinary PublicTransaction dispatch instead of the
separate ProgramDeploymentTransaction path.

Measured against every real program in this repo, computing a
program's image_id inside the zkVM costs ~1,400-1,500 cycles per byte
of deployed bytecode, pushing real deployments to 500M-900M cycles
against the 32M public-execution cap (vs. ~27ms natively, since
ProgramDeploymentTransaction's equivalent check runs as a plain host
function today). To keep the unified dispatch path viable, Deploy is
special-cased in from_public_transaction: calls targeting the reserved
RESERVED_DEPLOYMENT_PROGRAM_ACCOUNT_ID run loader_core::execute_deploy
natively instead of through the interpreted guest executor, wrapped in
catch_unwind since the shared execute_deploy logic validates via
assert!/expect() like every other guest program, relying on that
boundary instead of the zkVM's own panic-to-Result conversion.

The loader guest binary is kept buildable and covered by a test that
runs it for real and asserts its output matches the native path
exactly, so the two can't silently drift apart.
2026-08-22 17:39:13 -04:00
Marvin Jones 373c651c03 refactor(lee): migrate program self/caller identity from ProgramId to AccountId
ProgramInput/ProgramOutput.self_program_id/caller_program_id, and the
dispatcher's CallerData.program_id, now carry AccountId (renamed to
self_account_id/caller_account_id) instead of ProgramId. These fields
are self-reported/cross-checked dispatch bookkeeping, not RISC0 image
identity, and AccountId already crosses the guest/host boundary this
way via every pre_state.account_id.

ProgramId is now confined to what's actually image-id-keyed:
env::verify, Program.id (from compute_image_id()), and the
for_public_pda/for_private_pda derivation formulas, each recovering
the real ProgramId from AccountId via the existing bijection exactly
where needed.

Rebuilds artifacts and the prebuilt sequencer db fixture to match.
2026-08-22 17:39:13 -04:00
Marvin Jones 76587f65fc 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.
2026-08-22 17:39:13 -04:00
Marvin JonesandClaude Sonnet 5 5619a0a815 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>
2026-08-22 17:39:13 -04:00
Marvin Jones 90a3ee7812 refactor(lee): migrate program self/caller identity from ProgramId to AccountId
ProgramInput/ProgramOutput.self_program_id/caller_program_id, and the
dispatcher's CallerData.program_id, now carry AccountId (renamed to
self_account_id/caller_account_id) instead of ProgramId. These fields
are self-reported/cross-checked dispatch bookkeeping, not RISC0 image
identity, and AccountId already crosses the guest/host boundary this
way via every pre_state.account_id.

ProgramId is now confined to what's actually image-id-keyed:
env::verify, Program.id (from compute_image_id()), and the
for_public_pda/for_private_pda derivation formulas, each recovering
the real ProgramId from AccountId via the existing bijection exactly
where needed.

Rebuilds artifacts and the prebuilt sequencer db fixture to match.
2026-08-22 16:58:50 -04:00
Marvin Jones b9152f58c0 refactor(lee): migrate ChainedCall/Message program reference from ProgramId to AccountId
Chained-call and public-transaction dispatch now address the target
program directly by AccountId instead of routing through ProgramId and
converting internally, closing the gap that blocked PDA-addressed
program invocation. The field is named program_account_id (not
account_id) to stay unambiguous next to the account_ids list it sits
beside in the same structs.

Execution/PDA-derivation logic that fundamentally needs the RISC0 image
id (self_program_id, caller_program_id, env::verify, PDA seed
derivation) stays ProgramId-typed, recovering it from the dispatched
AccountId via the existing bijection where needed.
2026-08-22 16:58:27 -04:00
Marvin Jones 2094e59808 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.
2026-08-22 16:57:32 -04:00
Marvin Jones fecb6d8b78 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.
2026-08-22 16:57:32 -04:00
Marvin JonesandClaude Sonnet 5 dd87a9ecfe 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>
2026-08-22 16:57:32 -04:00
Marvin Jones 1496f6dd60 fix(lee): silence pedantic/restriction lints on DATA_MAX_LENGTH_BYTES's const cast
usize::try_from isn't const-stable yet, so the as-cast is unavoidable
here; mirrors the identical #[expect(...)] already used for
SeenShard::MAX_DELIVERIES's const cast in cross_zone_inbox/core.
2026-08-22 16:35:25 -04:00
Marvin Jones a76421d212 fix(lee): add DATA_MAX_LENGTH_BYTES const, drop repeated usize::try_from conversions
DATA_MAX_LENGTH_BYTES is a real const (ByteSize::as_u64 is const fn,
so no fallible conversion needed), replacing the private
data_max_length() helper and every duplicate
usize::try_from(DATA_MAX_LENGTH.as_u64()).expect(...) call site
across data.rs and its two external consumers, per PR #756 review nit.
2026-08-22 16:34:50 -04:00
Marvin Jones c453577e1c fix(lee): reuse check_len in Data's visit_seq path
Push-then-check instead of a pre-push >= comparison duplicating the
cap logic that check_len already applies elsewhere, per PR #756
review nit.
2026-08-22 16:34:50 -04:00
Marvin Jones 283a9bf685 docs(lee): trim encryption comments down to what isn't already in the PR description 2026-08-22 16:34:50 -04:00
Marvin Jones f3b53a267c docs(lee): make encryption's doc comments self-contained
Drop cross-references to account::data::Data and the -7-2 branch name —
the reasoning stands on its own within this module.
2026-08-22 16:34:50 -04:00
Marvin Jones 8b87212f02 feat(lee): apply the same RISC0 word-packing fix to EphemeralPublicKey and Ciphertext
Same derived-Serialize word-per-byte overhead Data had, on the same
guest-boundary path (both only ever reach a real, packed decode as the
prover's own PrivacyPreservingCircuitInput — never decoded from untrusted
bytes by a verifier, same audit as Data's). No new length cap added here,
unlike Data: neither type has one today, and tests deliberately construct
malformed-length values to exercise later, use-site rejection.
2026-08-22 16:34:50 -04:00
Marvin Jones 7b4ba87ece docs(lee): keep the eager-allocation safety rationale in Data's deserialize comment
Trimmed comment prose, but restore the "why" for the RISC0 binary path's
post-hoc (not preventive) cap check — the answer to "why isn't this a DoS
bug" is the load-bearing part.
2026-08-22 16:34:50 -04:00
Marvin Jones 8b1b147499 feat(lee): pack Account::data densely on the RISC0 word wire instead of one word per byte
Data's serde impls went through the generic per-element seq path, costing a
full 4-byte word per byte when crossing risc0_zkvm::serde (guest I/O, journal
commits, proving) — real cycle cost on every execution/proof touching an
account with non-trivial data, not just a wire-size issue. Routes through
serialize_bytes/deserialize_bytes instead, packing 4 bytes/word (~4x fewer
words), while keeping the existing incremental DATA_MAX_LENGTH check for the
human-readable (JSON) path and staying wire-compatible with the one
production JSON consumer (getAccount).

Rebuilds all committed guest artifacts and the test fixture dump, required
since the encoding change touches the guest-embedded wire format itself.
2026-08-22 16:34:50 -04: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
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
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
agureev d05035eb9e refactor(lee): refactor private kinds 2026-08-04 15:55:09 +04:00
agureev 0e957b5c08 chore: docs for PrivateAction commitment field 2026-07-31 00:47:04 +04: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 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 2999288a57 test(lee): pin for_dummy nullifier and commitment derivations 2026-07-24 16:38:04 +00:00
Artem Gureev 5d13e0acc5 feat(circuit): use dummy_inputs in ppc 2026-07-24 16:36:13 +00:00
Artem Gureev 31a17d74a3 feat(lee): add for_dummy nullifier and commitment derivations 2026-07-24 16:36:13 +00:00
Artem Gureev b9c03d3805 feat(lee): add dummy account type for function-privacy padding 2026-07-24 16:36:13 +00:00
jonesmarvin8andClaude Sonnet 5 6c0bd71523 refactor: PrivateUnauthorized authorization changed to true (#621)
* refactor: rename PrivateUnauthorized to PrivateForeignInit

The account_identity's is_authorized flag no longer determines
authorization for this variant, so keep the name tied to what
actually distinguishes it: no nsk, only npk (a foreign account init).

* chore: rebuild guest artifacts and bump spin to clear yanked advisory

Regenerate ELF artifacts after the PrivateForeignInit rename in lee_core
(compiled into every guest program), and update spin 0.9.8 -> 0.9.9 since
0.9.8 was yanked from crates.io, per cargo deny check advisories.

* test: align is_authorized with PrivateForeignInit's flipped semantics

Recipient pre-states built for PrivateForeignInit now need is_authorized:
true to match the assertion in output.rs. Also rewrites the boundary test
that checked the old invalid case to check the new one, and updates
stale "unauthorized" wording left over from the PrivateUnauthorized name.

* chore: rebuild guest artifacts

Reproducible across repeated local builds; likely toolchain drift since
the prior artifact commit rather than a source change, since no
guest-relevant source or Cargo.lock changed in between.

* fix(tests): align integration tests with PrivateForeignInit and regenerate fixture

prove_init_with_commitment_root (private.rs) and build_privacy_transaction
(tps.rs) still built PrivateForeignInit recipients with is_authorized: false,
same stale-semantics bug fixed earlier in the lee crate's own tests.

The prebuilt sequencer DB dump embeds program IDs derived from guest ELF
bytes, which shifted once the PrivateForeignInit rename changed lee_core
(compiled into every guest program). The stale dump caused widespread
"Unknown program" failures across integration test suites that exercise
deployed programs (wallet_ffi, auth_transfer, bridge, amm, token, pinata,
ata, indexer state-consistency checks). Regenerated via
`just regenerate-test-fixture`.

* fix(tests): rename leftover PrivateUnauthorized to PrivateForeignInit and regenerate fixture

* test: align is_authorized with PrivateForeignInit's flipped semantics

* chore: regenerate test fixture after rebase onto dev

* chore: regenerate test fixture after rebase onto dev

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

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 17:32:01 -04:00
agureev 61cad70f9b feat(circuit): supply a view_tag on private-account updates 2026-07-22 22:31:31 +04:00
Pravdyvy ac2bf7f996 Merge branch 'dev' into Pravdyvy/multi-sequencer-client 2026-07-14 13:19:04 +03:00
Pravdyvy 1615a06604 fix(wallet_ffi): tests and leading algorithm fixes 2026-07-13 15:37:25 +03:00
agureev bf86d0c05b Merge remote-tracking branch 'origin/dev' into artem/change-wallet-balance-fetch 2026-07-08 22:55:15 +04:00
agureev 8e084e22d1 Merge remote-tracking branch 'origin/dev' into artem/viewing-key-binding 2026-07-02 20:04:30 +04:00
agureev 296afdc4a3 Merge remote-tracking branch 'origin/dev' into artem/change-wallet-balance-fetch 2026-07-01 21:12:14 +04:00
Artem Gureev 6283f5e3ee refactor(state_machine): derive Default for ValidityWindow 2026-07-01 19:16:44 +04:00
jonesmarvin8 072ea3b066 refactor(lee::state_machine): clean up long functions and files (#535)
* refactor(lee): split large modules into directories and extract tests

Split state.rs, program.rs, circuit.rs, validated_state_diff.rs,
merkle_tree, and core/program.rs into module directories with separate
test files. State tests are further split into themed files (genesis,
authenticated_transfer, circuit, claiming, etc.). Extract
authenticate_public_transaction_signers helper in validated_state_diff
to remove duplicated authentication logic.

* chore: rebuild artifacts
2026-07-01 11:11:08 -04:00
jonesmarvin8 f8d859394b refactor(privacy_preserving_circuit): introduce helper functions to shorten long functions (#545)
* refactor(privacy_preserving_circuit): extract functions for readability

* refactor(privacy_preserving_circuit): address PR review comments

Bundle shared handle_* arguments into PrivateOutputHandler struct in
output.rs and fix misplaced docstring on resolve_external_seed in
execution_state.rs.

* feat: update commitment mechanism for new private account (#546)

* refactor(privacy_preserving_circuit): extract functions for readability

* feat: update commitment mechanism for new private accounts

Allow init accounts to optionally use a real membership proof for
DUMMY_COMMITMENT instead of hardcoding DUMMY_COMMITMENT_HASH as the
CommitmentSetDigest. The wallet fetches the proof from the sequencer
and passes it through the circuit.

* fix: address clippy lints and fix integration test visibility

* add tests

* refactor: removed duplicated code

* refactor: simplify init nullifier mechanism

Replace Option<MembershipProof> with Option<CommitmentSetDigest> on init
variants (PrivateAuthorizedInit, PrivateUnauthorized, PrivatePdaInit).
The circuit now receives the commitment tree root directly instead of
recomputing it from a Merkle proof.

* refactor: use CommitmentSetDigest directly instead of Option for init commitment root

Address PR #546 review feedback: the circuit now accepts CommitmentSetDigest
directly on init variants (PrivateAuthorizedInit, PrivateUnauthorized,
PrivatePdaInit), with callers providing DUMMY_COMMITMENT_HASH as the default.
Also fixes duplicate resolve_external_seed from rebase and rebuilds artifacts.

* style: run cargo +nightly fmt
2026-07-01 10:14:32 -04:00