diff --git a/.deny.toml b/.deny.toml index 59df488b..eef90d76 100644 --- a/.deny.toml +++ b/.deny.toml @@ -15,7 +15,11 @@ ignore = [ { id = "RUSTSEC-2023-0089", reason = "atomic-polyfill is pulled transitively via risc0-zkvm; waiting on upstream fix (see https://github.com/risc0/risc0/issues/3453)" }, { id = "RUSTSEC-2026-0118", reason = "`hickory-proto` v0.25.0-alpha.5 is present transitively from logos crates, modification may break integration" }, { id = "RUSTSEC-2026-0119", reason = "`hickory-proto` v0.25.0-alpha.5 is present transitively from logos crates, modification may break integration" }, + { id = "RUSTSEC-2025-0137", reason = "newest `rint` depends on rustc v1.90.0 and we build artifacts with v1.88.8" }, + + { id = "RUSTSEC-2024-0370", reason = "transitive dependency of `logos-blockchain-http-api-common`, can't do anything than wait for upstream fix" }, +>>>>>>> refs/rewritten/onto ] yanked = "deny" unused-ignored-advisory = "deny" @@ -56,6 +60,7 @@ unused-allowed-license = "deny" allow-git = [ "https://github.com/EspressoSystems/jellyfish.git", "https://github.com/logos-blockchain/logos-blockchain.git", + "https://github.com/logos-blockchain/logos-blockchain-circuits.git", ] unknown-git = "deny" unknown-registry = "deny" diff --git a/.github/actions/install-logos-blockchain-circuits/action.yaml b/.github/actions/install-logos-blockchain-circuits/action.yaml index e62aea6b..9356ac5c 100644 --- a/.github/actions/install-logos-blockchain-circuits/action.yaml +++ b/.github/actions/install-logos-blockchain-circuits/action.yaml @@ -16,4 +16,4 @@ runs: env: GITHUB_TOKEN: ${{ inputs.github-token }} run: | - curl -sSL https://raw.githubusercontent.com/logos-blockchain/logos-blockchain/main/scripts/setup-logos-blockchain-circuits.sh | bash + curl -sSL https://raw.githubusercontent.com/logos-blockchain/logos-blockchain/6ac348bea4160ca708b70a86b3964e9f1ce82fff/scripts/setup-logos-blockchain-circuits.sh | bash diff --git a/.github/workflows/bench-regression.yml b/.github/workflows/bench-regression.yml index 994989bf..d5d9568a 100644 --- a/.github/workflows/bench-regression.yml +++ b/.github/workflows/bench-regression.yml @@ -2,8 +2,8 @@ on: pull_request: paths: - "tools/crypto_primitives_bench/**" - - "key_protocol/**" - - "nssa/core/**" + - "lez/key_protocol/**" + - "lee/core/**" - ".github/workflows/bench-regression.yml" permissions: diff --git a/.github/workflows/publish_images.yml b/.github/workflows/publish_images.yml index dbf6a68d..bfddda6b 100644 --- a/.github/workflows/publish_images.yml +++ b/.github/workflows/publish_images.yml @@ -13,18 +13,18 @@ jobs: matrix: include: - name: sequencer_service - dockerfile: ./sequencer/service/Dockerfile + dockerfile: ./lez/sequencer/service/Dockerfile build_args: | STANDALONE=false - name: sequencer_service-standalone - dockerfile: ./sequencer/service/Dockerfile + dockerfile: ./lez/sequencer/service/Dockerfile build_args: | STANDALONE=true - name: indexer_service - dockerfile: ./indexer/service/Dockerfile + dockerfile: ./lez/indexer/service/Dockerfile build_args: "" - name: explorer_service - dockerfile: ./explorer_service/Dockerfile + dockerfile: ./lez/explorer_service/Dockerfile build_args: "" steps: - uses: actions/checkout@v5 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 41bb535d..284e3798 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,9 +27,9 @@ Allowed `type` values: - `revert` Examples: -- `feat(nssa): add private PDA support` +- `feat(lee): add private PDA support` - `fix(wallet): correct fee calculation` -- `feat(nssa)!: rename AccountId::from((prog, seed)) to AccountId::for_public_pda` +- `feat(lee)!: rename AccountId::from((prog, seed)) to AccountId::for_public_pda` Breaking changes: - Mark with `!` in the title. diff --git a/Cargo.lock b/Cargo.lock index 5e02cf77..d5ce6321 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -111,7 +111,7 @@ name = "amm_core" version = "0.1.0" dependencies = [ "borsh", - "nssa_core", + "lee_core", "risc0-zkvm", "serde", ] @@ -121,8 +121,8 @@ name = "amm_program" version = "0.1.0" dependencies = [ "amm_core", - "nssa", - "nssa_core", + "lee", + "lee_core", "token_core", ] @@ -273,7 +273,7 @@ dependencies = [ "ark-std 0.4.0", "blake2", "derivative", - "digest", + "digest 0.10.7", "sha2", ] @@ -293,7 +293,7 @@ dependencies = [ "ark-std 0.5.0", "blake2", "derivative", - "digest", + "digest 0.10.7", "fnv", "merlin", "sha2", @@ -359,7 +359,7 @@ dependencies = [ "ark-serialize 0.4.2", "ark-std 0.4.0", "derivative", - "digest", + "digest 0.10.7", "itertools 0.10.5", "num-bigint 0.4.6", "num-traits", @@ -379,7 +379,7 @@ dependencies = [ "ark-serialize 0.5.0", "ark-std 0.5.0", "arrayvec", - "digest", + "digest 0.10.7", "educe", "itertools 0.13.0", "num-bigint 0.4.6", @@ -541,7 +541,7 @@ checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" dependencies = [ "ark-serialize-derive 0.4.2", "ark-std 0.4.0", - "digest", + "digest 0.10.7", "num-bigint 0.4.6", ] @@ -554,7 +554,7 @@ dependencies = [ "ark-serialize-derive 0.5.0", "ark-std 0.5.0", "arrayvec", - "digest", + "digest 0.10.7", "num-bigint 0.4.6", ] @@ -733,8 +733,6 @@ checksum = "86887daca11d02e0b04f37a9cb81888aae881397fb48ff66494e356aea97554a" dependencies = [ "itertools 0.10.5", "lazy_static", - "rand 0.8.6", - "serde", ] [[package]] @@ -845,7 +843,7 @@ dependencies = [ name = "ata_core" version = "0.1.0" dependencies = [ - "nssa_core", + "lee_core", "risc0-zkvm", "serde", ] @@ -855,7 +853,7 @@ name = "ata_program" version = "0.1.0" dependencies = [ "ata_core", - "nssa_core", + "lee_core", "token_core", ] @@ -892,7 +890,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16e2cdb6d5ed835199484bb92bb8b3edd526effe995c61732580439c1a67e2e9" dependencies = [ "base64", - "http 1.4.0", + "http 1.4.1", "log", "url", ] @@ -950,7 +948,7 @@ dependencies = [ "axum-core 0.4.5", "bytes", "futures-util", - "http 1.4.0", + "http 1.4.1", "http-body", "http-body-util", "hyper", @@ -984,7 +982,7 @@ dependencies = [ "bytes", "form_urlencoded", "futures-util", - "http 1.4.0", + "http 1.4.1", "http-body", "http-body-util", "hyper", @@ -1019,7 +1017,7 @@ dependencies = [ "async-trait", "bytes", "futures-util", - "http 1.4.0", + "http 1.4.1", "http-body", "http-body-util", "mime", @@ -1038,7 +1036,7 @@ checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" dependencies = [ "bytes", "futures-core", - "http 1.4.0", + "http 1.4.1", "http-body", "http-body-util", "mime", @@ -1056,7 +1054,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cffb0e931875b666fc4fcb20fee52e9bbd1ef836fd9e9e04ec21555f9f85f7ef" dependencies = [ "fastrand", - "gloo-timers 0.3.0", "tokio", ] @@ -1121,7 +1118,7 @@ version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "cexpr", "clang-sys", "itertools 0.13.0", @@ -1129,7 +1126,7 @@ dependencies = [ "quote", "regex", "rustc-hash", - "shlex", + "shlex 1.3.0", "syn 2.0.117", ] @@ -1152,9 +1149,9 @@ checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bitcoin_hashes" -version = "0.14.1" +version = "0.14.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26ec84b80c482df901772e931a9a681e26a1b9ee2302edeff23cb30328745c8b" +checksum = "0c9901a56e133a1fc86eeb1113e2591f45f4682451ca893bff494d2f88918e3f" dependencies = [ "hex-conservative", ] @@ -1167,9 +1164,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.11.1" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" +checksum = "84d7ced0ae9557296835c32bf1b1e02b44c746701f898460fb000d7eaa84f00a" [[package]] name = "bitvec" @@ -1189,7 +1186,7 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" dependencies = [ - "digest", + "digest 0.10.7", ] [[package]] @@ -1224,7 +1221,7 @@ checksum = "ee04c4c84f1f811b017f2fbb7dd8815c976e7ca98593de9c1e2afad0f636bff4" dependencies = [ "async-stream", "base64", - "bitflags 2.11.1", + "bitflags 2.12.1", "bollard-buildkit-proto", "bollard-stubs", "bytes", @@ -1232,7 +1229,7 @@ dependencies = [ "futures-util", "hex", "home", - "http 1.4.0", + "http 1.4.1", "http-body-util", "hyper", "hyper-named-pipe", @@ -1314,6 +1311,14 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "bridge_core" +version = "0.1.0" +dependencies = [ + "lee_core", + "serde", +] + [[package]] name = "bs58" version = "0.5.1" @@ -1325,9 +1330,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.20.2" +version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" [[package]] name = "bytemuck" @@ -1423,9 +1428,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cbindgen" -version = "0.29.2" +version = "0.29.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "befbfd072a8e81c02f8c507aefce431fe5e7d051f83d48a23ffc9b9fe5a11799" +checksum = "c95537b45400390270fae69ac098d057c8f5399001cde9d04f700c105ddfff2d" dependencies = [ "clap", "heck", @@ -1442,14 +1447,14 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.62" +version = "1.2.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98" +checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f" dependencies = [ "find-msvc-tools", "jobserver", "libc", - "shlex", + "shlex 2.0.1", ] [[package]] @@ -1609,9 +1614,15 @@ name = "clock_core" version = "0.1.0" dependencies = [ "borsh", - "nssa_core", + "lee_core", ] +[[package]] +name = "cmov" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" + [[package]] name = "cobs" version = "0.3.0" @@ -1664,10 +1675,10 @@ dependencies = [ "borsh", "clock_core", "hex", + "lee", + "lee_core", "log", "logos-blockchain-common-http-client", - "nssa", - "nssa_core", "serde", "serde_with", "sha2", @@ -1730,9 +1741,9 @@ dependencies = [ [[package]] name = "const-hex" -version = "1.19.0" +version = "1.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20d9a563d167a9cce0f94153382b33cb6eded6dfabff03c69ad65a28ea1514e0" +checksum = "33e2a781ebdf4467d1428dc4593067825fb646f6871475098d8577421af73558" dependencies = [ "cfg-if", "cpufeatures 0.2.17", @@ -1746,6 +1757,12 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + [[package]] name = "const-str" version = "0.4.3" @@ -2013,7 +2030,9 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" dependencies = [ + "getrandom 0.4.2", "hybrid-array", + "rand_core 0.10.1", ] [[package]] @@ -2022,7 +2041,7 @@ version = "0.1.0" dependencies = [ "criterion", "key_protocol", - "nssa_core", + "lee_core", "rand 0.8.6", ] @@ -2035,6 +2054,15 @@ dependencies = [ "cipher 0.4.4", ] +[[package]] +name = "ctutils" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +dependencies = [ + "cmov", +] + [[package]] name = "curve25519-dalek" version = "4.1.3" @@ -2044,7 +2072,7 @@ dependencies = [ "cfg-if", "cpufeatures 0.2.17", "curve25519-dalek-derive", - "digest", + "digest 0.10.7", "fiat-crypto", "rustc_version", "serde", @@ -2075,8 +2103,8 @@ dependencies = [ "clap", "clock_core", "criterion", - "nssa", - "nssa_core", + "lee", + "lee_core", "risc0-zkvm", "serde", "serde_json", @@ -2184,11 +2212,21 @@ version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ - "const-oid", + "const-oid 0.9.6", "pem-rfc7468", "zeroize", ] +[[package]] +name = "der" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fd89660b2dc699704064e59e9dba0147b903e85319429e131620d022be411b" +dependencies = [ + "const-oid 0.10.2", + "zeroize", +] + [[package]] name = "der-parser" version = "10.0.0" @@ -2307,11 +2345,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.4", - "const-oid", + "const-oid 0.9.6", "crypto-common 0.1.7", "subtle", ] +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.0", + "crypto-common 0.2.2", +] + [[package]] name = "directories" version = "6.0.0" @@ -2344,9 +2392,9 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" dependencies = [ "proc-macro2", "quote", @@ -2405,7 +2453,7 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ac1e888d6830712d565b2f3a974be3200be9296bc1b03db8251a4cbf18a4a34" dependencies = [ - "digest", + "digest 0.10.7", "futures", "rand 0.8.6", "reqwest", @@ -2437,13 +2485,13 @@ version = "0.16.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ - "der", - "digest", + "der 0.7.10", + "digest 0.10.7", "elliptic-curve", "rfc6979", "serdect", "signature", - "spki", + "spki 0.7.3", ] [[package]] @@ -2452,7 +2500,7 @@ version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ - "pkcs8", + "pkcs8 0.10.2", "serde", "signature", ] @@ -2514,12 +2562,12 @@ checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ "base16ct", "crypto-bigint", - "digest", + "digest 0.10.7", "ff", "generic-array 0.14.7", "group", "pem-rfc7468", - "pkcs8", + "pkcs8 0.10.2", "rand_core 0.6.4", "sec1", "serdect", @@ -2659,7 +2707,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -2706,7 +2754,7 @@ version = "0.1.0" dependencies = [ "bytemuck", "hex", - "nssa_core", + "lee_core", "risc0-zkvm", ] @@ -2753,10 +2801,21 @@ checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" name = "faucet_core" version = "0.1.0" dependencies = [ - "nssa_core", + "lee_core", "serde", ] +[[package]] +name = "fd-lock" +version = "4.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78" +dependencies = [ + "cfg-if", + "rustix", + "windows-sys 0.59.0", +] + [[package]] name = "ferroid" version = "2.0.0" @@ -2840,6 +2899,15 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared 0.1.1", +] + [[package]] name = "foreign-types" version = "0.5.0" @@ -2847,7 +2915,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" dependencies = [ "foreign-types-macros", - "foreign-types-shared", + "foreign-types-shared 0.3.1", ] [[package]] @@ -2861,6 +2929,12 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "foreign-types-shared" version = "0.3.1" @@ -2990,7 +3064,7 @@ version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af43fadb8a98512d547e37b4e92e0ced13e205c061b87b4623eff01d918d6968" dependencies = [ - "gloo-timers 0.4.0", + "gloo-timers", "send_wrapper", ] @@ -3017,7 +3091,7 @@ version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bafc7e33650ab9f05dcc16325f05d56b8d10393114e31a19a353b86fa60cfe7" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "cfg-if", "log", "managed", @@ -3048,9 +3122,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "1.4.1" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dab9e9188e97a93276e1fe7b56401b851e2b45a46d045ca658100c1303ada649" +checksum = "c2e55f16dcf0e9c00efbe2e655ffe45fc98e7066b52bc92f8a79e64060a79351" dependencies = [ "rustversion", "serde_core", @@ -3137,7 +3211,7 @@ dependencies = [ "futures-core", "futures-sink", "gloo-utils", - "http 1.4.0", + "http 1.4.1", "js-sys", "pin-project", "serde", @@ -3148,18 +3222,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "gloo-timers" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - [[package]] name = "gloo-timers" version = "0.4.0" @@ -3213,7 +3275,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http 1.4.0", + "http 1.4.1", "indexmap 2.14.0", "slab", "tokio", @@ -3421,7 +3483,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest", + "digest 0.10.7", ] [[package]] @@ -3472,9 +3534,9 @@ dependencies = [ [[package]] name = "http" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +checksum = "8be7462df143984c4598a256ef469b251d7d7f9e271135073e78fc535414f3d0" dependencies = [ "bytes", "itoa", @@ -3487,7 +3549,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.4.0", + "http 1.4.1", ] [[package]] @@ -3498,7 +3560,7 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http 1.4.0", + "http 1.4.1", "http-body", "pin-project-lite", ] @@ -3543,6 +3605,7 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9155a582abd142abc056962c29e3ce5ff2ad5469f4246b537ed42c5deba857da" dependencies = [ + "ctutils", "typenum", ] @@ -3564,16 +3627,16 @@ dependencies = [ [[package]] name = "hyper" -version = "1.9.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" +checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498" dependencies = [ "atomic-waker", "bytes", "futures-channel", "futures-core", "h2", - "http 1.4.0", + "http 1.4.1", "http-body", "httparse", "httpdate", @@ -3605,7 +3668,7 @@ version = "0.27.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" dependencies = [ - "http 1.4.0", + "http 1.4.1", "hyper", "hyper-util", "log", @@ -3629,6 +3692,22 @@ dependencies = [ "tower-service", ] +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + [[package]] name = "hyper-util" version = "0.1.20" @@ -3639,17 +3718,19 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.4.0", + "http 1.4.1", "http-body", "hyper", "ipnet", "libc", "percent-encoding", "pin-project-lite", - "socket2 0.5.10", + "socket2 0.6.4", + "system-configuration 0.7.0", "tokio", "tower-service", "tracing", + "windows-registry", ] [[package]] @@ -3849,7 +3930,7 @@ dependencies = [ "attohttpc 0.24.1", "bytes", "futures", - "http 1.4.0", + "http 1.4.1", "http-body-util", "hyper", "hyper-util", @@ -3870,7 +3951,7 @@ dependencies = [ "attohttpc 0.30.1", "bytes", "futures", - "http 1.4.0", + "http 1.4.1", "http-body-util", "hyper", "hyper-util", @@ -3898,11 +3979,11 @@ dependencies = [ "common", "futures", "humantime-serde", + "lee", + "lee_core", "log", "logos-blockchain-core", "logos-blockchain-zone-sdk", - "nssa", - "nssa_core", "serde", "serde_json", "storage", @@ -3922,8 +4003,8 @@ dependencies = [ "indexer_service_protocol", "indexer_service_rpc", "jsonrpsee", + "lee", "log", - "nssa", "tokio", "url", ] @@ -3956,8 +4037,8 @@ dependencies = [ "base64", "common", "hex", - "nssa", - "nssa_core", + "lee", + "lee_core", "schemars 1.2.1", "serde", "serde_with", @@ -4047,7 +4128,7 @@ dependencies = [ "common", "indexer_service_rpc", "jsonrpsee", - "nssa", + "lee", "sequencer_service_rpc", "serde", "serde_json", @@ -4063,6 +4144,8 @@ dependencies = [ "anyhow", "ata_core", "authenticated_transfer_core", + "borsh", + "bridge_core", "bytesize", "common", "faucet_core", @@ -4071,9 +4154,12 @@ dependencies = [ "indexer_service_protocol", "indexer_service_rpc", "key_protocol", + "lee", + "lee_core", "log", - "nssa", - "nssa_core", + "logos-blockchain-core", + "logos-blockchain-http-api-common", + "reqwest", "sequencer_core", "sequencer_service_rpc", "serde_json", @@ -4107,7 +4193,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d40460c0ce33d6ce4b0630ad68ff63d6661961c48b6dba35e5a4d81cfb48222" dependencies = [ - "socket2 0.6.3", + "socket2 0.6.4", "widestring", "windows-registry", "windows-result", @@ -4195,9 +4281,9 @@ dependencies = [ [[package]] name = "jiff" -version = "0.2.24" +version = "0.2.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f00b5dbd620d61dfdcb6007c9c1f6054ebd75319f163d886a9055cec1155073d" +checksum = "4603d3033e49e2b0e31229fcab20a5d40089c607d975cd9c80551dc69eed9102" dependencies = [ "jiff-static", "log", @@ -4208,9 +4294,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.24" +version = "0.2.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e000de030ff8022ea1da3f466fbb0f3a809f5e51ed31f6dd931c35181ad8e6d7" +checksum = "782d32378dddf207193ac91cefb848ad41abb58195c95168e1291227a0832b47" dependencies = [ "proc-macro2", "quote", @@ -4273,9 +4359,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.98" +version = "0.3.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08" +checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11" dependencies = [ "cfg-if", "futures-util", @@ -4311,7 +4397,7 @@ dependencies = [ "futures-channel", "futures-util", "gloo-net", - "http 1.4.0", + "http 1.4.1", "jsonrpsee-core", "pin-project", "rustls", @@ -4336,7 +4422,7 @@ dependencies = [ "bytes", "futures-timer", "futures-util", - "http 1.4.0", + "http 1.4.1", "http-body", "http-body-util", "jsonrpsee-types", @@ -4397,7 +4483,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c51b7c290bb68ce3af2d029648148403863b982f138484a73f02a9dd52dbd7f" dependencies = [ "futures-util", - "http 1.4.0", + "http 1.4.1", "http-body", "http-body-util", "hyper", @@ -4423,7 +4509,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc88ff4688e43cc3fa9883a8a95c6fa27aa2e76c96e610b737b6554d650d7fd5" dependencies = [ - "http 1.4.0", + "http 1.4.1", "serde", "serde_json", "thiserror 2.0.18", @@ -4447,7 +4533,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b6fceceeb05301cc4c065ab3bd2fa990d41ff4eb44e4ca1b30fa99c057c3e79" dependencies = [ - "http 1.4.0", + "http 1.4.1", "jsonrpsee-client-transport", "jsonrpsee-core", "jsonrpsee-types", @@ -4479,6 +4565,26 @@ dependencies = [ "cpufeatures 0.2.17", ] +[[package]] +name = "keccak" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e24a010dd405bd7ed803e5253182815b41bf2e6a80cc3bfc066658e03a198aa" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", +] + +[[package]] +name = "kem" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01737161ba802849cfd486b5bd209d38ba4943494c249a8126005170c7621edd" +dependencies = [ + "crypto-common 0.2.2", + "rand_core 0.10.1", +] + [[package]] name = "key_protocol" version = "0.1.0" @@ -4493,8 +4599,9 @@ dependencies = [ "hmac-sha512", "itertools 0.14.0", "k256", - "nssa", - "nssa_core", + "lee", + "lee_core", + "ml-kem", "rand 0.8.6", "serde", "sha2", @@ -4505,12 +4612,11 @@ dependencies = [ name = "keycard_wallet" version = "0.1.0" dependencies = [ + "lee", "log", - "nssa", "pyo3", "serde", "serde_json", - "zeroize", ] [[package]] @@ -4566,6 +4672,52 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" +[[package]] +name = "lee" +version = "0.1.0" +dependencies = [ + "anyhow", + "authenticated_transfer_core", + "borsh", + "bridge_core", + "clock_core", + "env_logger", + "faucet_core", + "hex", + "hex-literal 1.1.0", + "k256", + "lee_core", + "log", + "rand 0.8.6", + "risc0-binfmt", + "risc0-build", + "risc0-zkvm", + "serde", + "serde_with", + "sha2", + "test-case", + "test_program_methods", + "thiserror 2.0.18", + "token_core", +] + +[[package]] +name = "lee_core" +version = "0.1.0" +dependencies = [ + "base58", + "borsh", + "bytemuck", + "bytesize", + "chacha20", + "ml-kem", + "risc0-zkvm", + "serde", + "serde_json", + "serde_with", + "thiserror 2.0.18", +] + [[package]] name = "leptos" version = "0.8.19" @@ -4788,6 +4940,14 @@ dependencies = [ "tachys", ] +[[package]] +name = "lez" +version = "0.1.0" +dependencies = [ + "indexer_core", + "sequencer_core", +] + [[package]] name = "libc" version = "0.2.186" @@ -5005,9 +5165,9 @@ dependencies = [ [[package]] name = "libp2p-identity" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c7892c221730ba55f7196e98b0b8ba5e04b4155651736036628e9f73ed6fc3" +checksum = "9525f3831544f7ae497bde79adf114ef127b0fbbb97edbbf692a80408636421c" dependencies = [ "asn1_der", "bs58", @@ -5015,7 +5175,7 @@ dependencies = [ "hkdf", "k256", "multihash", - "quick-protobuf", + "prost 0.14.3", "rand 0.8.6", "serde", "sha2", @@ -5229,9 +5389,9 @@ dependencies = [ [[package]] name = "libredox" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c" +checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3" dependencies = [ "libc", ] @@ -5251,9 +5411,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.28" +version = "1.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc3a226e576f50782b3305c5ccf458698f92798987f551c6a02efe8276721e22" +checksum = "85bc9657773828b90eeb625adff10eeac83cc21bbfd8e23a03eaa8a33c9e28d9" dependencies = [ "cc", "pkg-config", @@ -5295,14 +5455,14 @@ dependencies = [ [[package]] name = "log" -version = "0.4.29" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "113b30b4cd05f7c06868fdb2854f66a7b9fece9a48425351cd532e810d74024f" [[package]] name = "logos-blockchain-blend-crypto" version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" dependencies = [ "blake2", "logos-blockchain-groth16", @@ -5310,13 +5470,13 @@ dependencies = [ "logos-blockchain-poseidon2", "logos-blockchain-utils", "rs-merkle-tree", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] name = "logos-blockchain-blend-message" version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" dependencies = [ "blake2", "derivative", @@ -5327,11 +5487,12 @@ dependencies = [ "logos-blockchain-core", "logos-blockchain-groth16", "logos-blockchain-key-management-system-keys", + "logos-blockchain-log-targets", "logos-blockchain-utils", "serde", "serde-big-array", "serde_with", - "thiserror 1.0.69", + "thiserror 2.0.18", "tracing", "zeroize", ] @@ -5339,26 +5500,27 @@ dependencies = [ [[package]] name = "logos-blockchain-blend-proofs" version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" dependencies = [ "ed25519-dalek", - "generic-array 1.4.1", + "generic-array 1.4.3", "hex", "logos-blockchain-blend-crypto", "logos-blockchain-groth16", "logos-blockchain-pol", "logos-blockchain-poq", + "logos-blockchain-poseidon2", "logos-blockchain-utils", "num-bigint 0.4.6", "serde", - "thiserror 1.0.69", + "thiserror 2.0.18", "zeroize", ] [[package]] name = "logos-blockchain-chain-broadcast-service" version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" dependencies = [ "async-trait", "derivative", @@ -5374,7 +5536,7 @@ dependencies = [ [[package]] name = "logos-blockchain-chain-service" version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" dependencies = [ "async-trait", "bytes", @@ -5396,25 +5558,95 @@ dependencies = [ "serde", "serde_with", "strum", - "thiserror 1.0.69", + "thiserror 2.0.18", + "time", "tokio", "tracing", "tracing-futures", ] +[[package]] +name = "logos-blockchain-circuits-build" +version = "0.5.0" +source = "git+https://github.com/logos-blockchain/logos-blockchain-circuits.git?rev=2e79ac30831d89e6a349720c08d5b8b9978970e0#2e79ac30831d89e6a349720c08d5b8b9978970e0" +dependencies = [ + "dirs", + "fd-lock", + "flate2", + "tar", + "ureq", +] + +[[package]] +name = "logos-blockchain-circuits-common" +version = "0.5.0" +source = "git+https://github.com/logos-blockchain/logos-blockchain-circuits.git?rev=2e79ac30831d89e6a349720c08d5b8b9978970e0#2e79ac30831d89e6a349720c08d5b8b9978970e0" +dependencies = [ + "logos-blockchain-circuits-types", +] + +[[package]] +name = "logos-blockchain-circuits-poc-sys" +version = "0.5.0" +source = "git+https://github.com/logos-blockchain/logos-blockchain-circuits.git?rev=2e79ac30831d89e6a349720c08d5b8b9978970e0#2e79ac30831d89e6a349720c08d5b8b9978970e0" +dependencies = [ + "logos-blockchain-circuits-build", + "logos-blockchain-circuits-common", + "logos-blockchain-circuits-types", +] + +[[package]] +name = "logos-blockchain-circuits-pol-sys" +version = "0.5.0" +source = "git+https://github.com/logos-blockchain/logos-blockchain-circuits.git?rev=2e79ac30831d89e6a349720c08d5b8b9978970e0#2e79ac30831d89e6a349720c08d5b8b9978970e0" +dependencies = [ + "logos-blockchain-circuits-build", + "logos-blockchain-circuits-common", + "logos-blockchain-circuits-types", +] + +[[package]] +name = "logos-blockchain-circuits-poq-sys" +version = "0.5.0" +source = "git+https://github.com/logos-blockchain/logos-blockchain-circuits.git?rev=2e79ac30831d89e6a349720c08d5b8b9978970e0#2e79ac30831d89e6a349720c08d5b8b9978970e0" +dependencies = [ + "logos-blockchain-circuits-build", + "logos-blockchain-circuits-common", + "logos-blockchain-circuits-types", +] + [[package]] name = "logos-blockchain-circuits-prover" version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" dependencies = [ "logos-blockchain-circuits-utils", "tempfile", ] +[[package]] +name = "logos-blockchain-circuits-signature-sys" +version = "0.5.0" +source = "git+https://github.com/logos-blockchain/logos-blockchain-circuits.git?rev=2e79ac30831d89e6a349720c08d5b8b9978970e0#2e79ac30831d89e6a349720c08d5b8b9978970e0" +dependencies = [ + "logos-blockchain-circuits-build", + "logos-blockchain-circuits-common", + "logos-blockchain-circuits-types", +] + +[[package]] +name = "logos-blockchain-circuits-types" +version = "0.5.0" +source = "git+https://github.com/logos-blockchain/logos-blockchain-circuits.git?rev=2e79ac30831d89e6a349720c08d5b8b9978970e0#2e79ac30831d89e6a349720c08d5b8b9978970e0" +dependencies = [ + "bytes", + "libc", +] + [[package]] name = "logos-blockchain-circuits-utils" version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" dependencies = [ "dirs", ] @@ -5422,10 +5654,11 @@ dependencies = [ [[package]] name = "logos-blockchain-common-http-client" version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" dependencies = [ "futures", "hex", + "log", "logos-blockchain-chain-broadcast-service", "logos-blockchain-chain-service", "logos-blockchain-core", @@ -5435,14 +5668,15 @@ dependencies = [ "reqwest", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror 2.0.18", + "tokio-util", "url", ] [[package]] name = "logos-blockchain-core" version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" dependencies = [ "ark-ff 0.4.2", "bincode", @@ -5467,20 +5701,21 @@ dependencies = [ "rpds", "serde", "strum", - "thiserror 1.0.69", + "thiserror 2.0.18", + "time", "tracing", ] [[package]] name = "logos-blockchain-cryptarchia-engine" version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" dependencies = [ "logos-blockchain-pol", "logos-blockchain-utils", "serde", "serde_with", - "thiserror 1.0.69", + "thiserror 2.0.18", "time", "tokio", "tracing", @@ -5489,7 +5724,7 @@ dependencies = [ [[package]] name = "logos-blockchain-cryptarchia-sync" version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" dependencies = [ "bytes", "futures", @@ -5500,7 +5735,7 @@ dependencies = [ "rand 0.8.6", "serde", "serde_with", - "thiserror 1.0.69", + "thiserror 2.0.18", "tokio", "tracing", ] @@ -5508,14 +5743,14 @@ dependencies = [ [[package]] name = "logos-blockchain-groth16" version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" dependencies = [ "ark-bn254 0.4.0", "ark-ec 0.4.2", "ark-ff 0.4.2", "ark-groth16 0.4.0", "ark-serialize 0.4.2", - "generic-array 1.4.1", + "generic-array 1.4.3", "hex", "num-bigint 0.4.6", "serde", @@ -5526,7 +5761,7 @@ dependencies = [ [[package]] name = "logos-blockchain-http-api-common" version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" dependencies = [ "axum 0.7.9", "logos-blockchain-core", @@ -5534,19 +5769,24 @@ dependencies = [ "logos-blockchain-tracing", "serde", "serde_json", + "serde_urlencoded", "serde_with", + "time", "tracing", + "url", + "utoipa", + "validator", ] [[package]] name = "logos-blockchain-key-management-system-keys" version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" dependencies = [ "async-trait", "bytes", "ed25519-dalek", - "generic-array 1.4.1", + "generic-array 1.4.3", "hex", "logos-blockchain-groth16", "logos-blockchain-key-management-system-macros", @@ -5567,7 +5807,7 @@ dependencies = [ [[package]] name = "logos-blockchain-key-management-system-macros" version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" dependencies = [ "proc-macro2", "quote", @@ -5577,7 +5817,7 @@ dependencies = [ [[package]] name = "logos-blockchain-key-management-system-operators" version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" dependencies = [ "async-trait", "logos-blockchain-blend-proofs", @@ -5593,7 +5833,7 @@ dependencies = [ [[package]] name = "logos-blockchain-key-management-system-service" version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" dependencies = [ "async-trait", "log", @@ -5610,7 +5850,7 @@ dependencies = [ [[package]] name = "logos-blockchain-ledger" version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" dependencies = [ "derivative", "logos-blockchain-blend-crypto", @@ -5629,14 +5869,14 @@ dependencies = [ "rpds", "serde", "serde_arrays", - "thiserror 1.0.69", + "thiserror 2.0.18", "tracing", ] [[package]] name = "logos-blockchain-libp2p" version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" dependencies = [ "async-trait", "backon", @@ -5647,6 +5887,7 @@ dependencies = [ "igd-next 0.16.2", "libp2p", "logos-blockchain-cryptarchia-sync", + "logos-blockchain-log-targets", "logos-blockchain-utils", "multiaddr", "natpmp", @@ -5655,16 +5896,34 @@ dependencies = [ "rand 0.8.6", "serde", "serde_with", - "thiserror 1.0.69", + "thiserror 2.0.18", "tokio", "tracing", "zerocopy", ] +[[package]] +name = "logos-blockchain-log-targets" +version = "0.1.2" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" +dependencies = [ + "logos-blockchain-log-targets-macros", +] + +[[package]] +name = "logos-blockchain-log-targets-macros" +version = "0.1.2" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "logos-blockchain-mmr" version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" dependencies = [ "ark-ff 0.4.2", "logos-blockchain-groth16", @@ -5677,13 +5936,14 @@ dependencies = [ [[package]] name = "logos-blockchain-network-service" version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" dependencies = [ "async-trait", "futures", "logos-blockchain-core", "logos-blockchain-cryptarchia-sync", "logos-blockchain-libp2p", + "logos-blockchain-log-targets", "logos-blockchain-tracing", "overwatch", "rand 0.8.6", @@ -5697,48 +5957,52 @@ dependencies = [ [[package]] name = "logos-blockchain-poc" version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" dependencies = [ + "logos-blockchain-circuits-poc-sys", "logos-blockchain-circuits-prover", + "logos-blockchain-circuits-types", "logos-blockchain-circuits-utils", "logos-blockchain-groth16", - "logos-blockchain-witness-generator", + "logos-blockchain-proofs-error", "num-bigint 0.4.6", "serde", "serde_json", - "thiserror 2.0.18", "tracing", ] [[package]] name = "logos-blockchain-pol" version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" dependencies = [ "astro-float", + "logos-blockchain-circuits-pol-sys", "logos-blockchain-circuits-prover", + "logos-blockchain-circuits-types", "logos-blockchain-circuits-utils", "logos-blockchain-groth16", + "logos-blockchain-proofs-error", "logos-blockchain-utils", - "logos-blockchain-witness-generator", "num-bigint 0.4.6", "num-traits", "serde", "serde_json", - "thiserror 2.0.18", "tracing", ] [[package]] name = "logos-blockchain-poq" version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" dependencies = [ + "logos-blockchain-circuits-poq-sys", "logos-blockchain-circuits-prover", + "logos-blockchain-circuits-types", "logos-blockchain-circuits-utils", "logos-blockchain-groth16", "logos-blockchain-pol", - "logos-blockchain-witness-generator", + "logos-blockchain-proofs-error", "num-bigint 0.4.6", "serde", "serde_json", @@ -5749,7 +6013,7 @@ dependencies = [ [[package]] name = "logos-blockchain-poseidon2" version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" dependencies = [ "ark-bn254 0.4.0", "ark-ff 0.4.2", @@ -5757,10 +6021,21 @@ dependencies = [ "num-bigint 0.4.6", ] +[[package]] +name = "logos-blockchain-proofs-error" +version = "0.1.2" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" +dependencies = [ + "logos-blockchain-circuits-types", + "logos-blockchain-groth16", + "serde_json", + "thiserror 2.0.18", +] + [[package]] name = "logos-blockchain-services-utils" version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" dependencies = [ "async-trait", "futures", @@ -5768,24 +6043,25 @@ dependencies = [ "overwatch", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror 2.0.18", "tracing", ] [[package]] name = "logos-blockchain-storage-service" version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" dependencies = [ "async-trait", "bytes", "futures", "logos-blockchain-core", "logos-blockchain-cryptarchia-engine", + "logos-blockchain-log-targets", "logos-blockchain-tracing", "overwatch", "serde", - "thiserror 1.0.69", + "thiserror 2.0.18", "tokio", "tracing", ] @@ -5793,12 +6069,13 @@ dependencies = [ [[package]] name = "logos-blockchain-time-service" version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" dependencies = [ "async-trait", "futures", "log", "logos-blockchain-cryptarchia-engine", + "logos-blockchain-log-targets", "logos-blockchain-tracing", "logos-blockchain-utils", "overwatch", @@ -5815,8 +6092,10 @@ dependencies = [ [[package]] name = "logos-blockchain-tracing" version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" dependencies = [ + "flate2", + "logos-blockchain-log-targets", "opentelemetry", "opentelemetry-appender-tracing", "opentelemetry-http", @@ -5839,7 +6118,7 @@ dependencies = [ [[package]] name = "logos-blockchain-utils" version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" dependencies = [ "async-trait", "blake2", @@ -5850,13 +6129,15 @@ dependencies = [ "rand 0.8.6", "serde", "serde_with", + "serde_yaml", + "thiserror 2.0.18", "time", ] [[package]] name = "logos-blockchain-utxotree" version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" dependencies = [ "ark-ff 0.4.2", "logos-blockchain-groth16", @@ -5864,27 +6145,21 @@ dependencies = [ "num-bigint 0.4.6", "rpds", "serde", - "thiserror 1.0.69", -] - -[[package]] -name = "logos-blockchain-witness-generator" -version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" -dependencies = [ - "tempfile", + "thiserror 2.0.18", ] [[package]] name = "logos-blockchain-zksign" version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" dependencies = [ "logos-blockchain-circuits-prover", + "logos-blockchain-circuits-signature-sys", + "logos-blockchain-circuits-types", "logos-blockchain-circuits-utils", "logos-blockchain-groth16", "logos-blockchain-poseidon2", - "logos-blockchain-witness-generator", + "logos-blockchain-proofs-error", "num-bigint 0.4.6", "serde", "serde_json", @@ -5895,13 +6170,15 @@ dependencies = [ [[package]] name = "logos-blockchain-zone-sdk" version = "0.1.2" -source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=ee281a447d95a951752461ee0a6e88eb4a0f17cf#ee281a447d95a951752461ee0a6e88eb4a0f17cf" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=db9a8d821c1b20f29b03d02072817150cf969b8e#db9a8d821c1b20f29b03d02072817150cf969b8e" dependencies = [ "async-trait", "futures", + "hex", "logos-blockchain-common-http-client", "logos-blockchain-core", "logos-blockchain-groth16", + "logos-blockchain-http-api-common", "logos-blockchain-key-management-system-service", "rand 0.8.6", "reqwest", @@ -6083,9 +6360,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" [[package]] name = "memmap2" @@ -6119,7 +6396,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" dependencies = [ "byteorder", - "keccak", + "keccak 0.1.6", "rand_core 0.6.4", "zeroize", ] @@ -6130,10 +6407,10 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ecfd3296f8c56b7c1f6fbac3c71cefa9d78ce009850c45000015f206dc7fa21" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "block", "core-graphics-types", - "foreign-types", + "foreign-types 0.5.0", "log", "objc", "paste", @@ -6173,15 +6450,40 @@ dependencies = [ [[package]] name = "mio" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" +checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" dependencies = [ "libc", "wasi", "windows-sys 0.61.2", ] +[[package]] +name = "ml-kem" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e15f3e5b957493873e396a66914e83e616b6afe335cdef7efe5c6e1216aba66" +dependencies = [ + "hybrid-array", + "kem", + "module-lattice", + "pkcs8 0.11.0", + "rand_core 0.10.1", + "sha3", +] + +[[package]] +name = "module-lattice" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c61b87c9683ab7cb1c6871d261ad5479b6b10ceb52c4352aaca3b5d35a8febe" +dependencies = [ + "ctutils", + "hybrid-array", + "num-traits", +] + [[package]] name = "moka" version = "0.12.15" @@ -6208,7 +6510,7 @@ dependencies = [ "bytes", "encoding_rs", "futures-util", - "http 1.4.0", + "http 1.4.1", "httparse", "memchr", "mime", @@ -6271,6 +6573,23 @@ dependencies = [ "unsigned-varint 0.7.2", ] +[[package]] +name = "native-tls" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "natpmp" version = "0.5.0" @@ -6356,7 +6675,7 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ce3636fa715e988114552619582b530481fd5ef176a1e5c1bf024077c2c9445" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "libc", "log", "netlink-packet-core 0.8.1", @@ -6416,10 +6735,10 @@ dependencies = [ "ark-ec 0.4.2", "ark-ff 0.4.2", "ark-serialize 0.4.2", - "digest", + "digest 0.10.7", "generic-array 0.14.7", "hex", - "keccak", + "keccak 0.1.6", "log", "rand 0.8.6", "zeroize", @@ -6431,7 +6750,7 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "cfg-if", "cfg_aliases", "libc", @@ -6462,51 +6781,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "nssa" -version = "0.1.0" -dependencies = [ - "anyhow", - "authenticated_transfer_core", - "borsh", - "clock_core", - "env_logger", - "faucet_core", - "hex", - "hex-literal 1.1.0", - "k256", - "log", - "nssa_core", - "rand 0.8.6", - "risc0-binfmt", - "risc0-build", - "risc0-zkvm", - "serde", - "serde_with", - "sha2", - "test-case", - "test_program_methods", - "thiserror 2.0.18", - "token_core", -] - -[[package]] -name = "nssa_core" -version = "0.1.0" -dependencies = [ - "base58", - "borsh", - "bytemuck", - "bytesize", - "chacha20", - "k256", - "risc0-zkvm", - "serde", - "serde_json", - "serde_with", - "thiserror 2.0.18", -] - [[package]] name = "nu-ansi-term" version = "0.50.3" @@ -6727,12 +7001,49 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +[[package]] +name = "openssl" +version = "0.10.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a45fa2aa886c42762255da344f0a0d313e254066c46aad76f300c3d3da62d967" +dependencies = [ + "bitflags 2.12.1", + "cfg-if", + "foreign-types 0.3.2", + "libc", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "openssl-probe" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" +[[package]] +name = "openssl-sys" +version = "0.9.116" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28a22dc7140cda5f096e5e7724a6962ca81a7f8bfd2979f9b18c11af56318c4" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "opentelemetry" version = "0.31.0" @@ -6766,7 +7077,7 @@ checksum = "d7a6d09a73194e6b66df7c8f1b680f156d916a1a942abf2de06823dd02b7855d" dependencies = [ "async-trait", "bytes", - "http 1.4.0", + "http 1.4.1", "opentelemetry", "reqwest", ] @@ -6777,7 +7088,7 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f69cd6acbb9af919df949cd1ec9e5e7fdc2ef15d234b6b795aaa525cc02f71f" dependencies = [ - "http 1.4.0", + "http 1.4.1", "opentelemetry", "opentelemetry-http", "opentelemetry-proto", @@ -7014,9 +7325,9 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" dependencies = [ - "der", - "pkcs8", - "spki", + "der 0.7.10", + "pkcs8 0.10.2", + "spki 0.7.3", ] [[package]] @@ -7025,8 +7336,18 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ - "der", - "spki", + "der 0.7.10", + "spki 0.7.3", +] + +[[package]] +name = "pkcs8" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "451913da69c775a56034ea8d9003d27ee8948e12443eae7c038ba100a4f21cb7" +dependencies = [ + "der 0.8.0", + "spki 0.8.0", ] [[package]] @@ -7157,7 +7478,31 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" dependencies = [ - "toml_edit 0.25.11+spec-1.1.0", + "toml_edit 0.25.12+spec-1.1.0", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", ] [[package]] @@ -7221,8 +7566,8 @@ version = "0.1.0" dependencies = [ "clap", "common", - "nssa", - "nssa_core", + "lee", + "lee_core", "sequencer_service_rpc", "tokio", "wallet", @@ -7244,9 +7589,10 @@ dependencies = [ "ata_core", "ata_program", "authenticated_transfer_core", + "bridge_core", "clock_core", "faucet_core", - "nssa_core", + "lee_core", "risc0-zkvm", "serde", "token_core", @@ -7283,7 +7629,7 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "num-traits", "rand 0.9.4", "rand_chacha 0.9.0", @@ -7468,7 +7814,7 @@ dependencies = [ "quinn-udp", "rustc-hash", "rustls", - "socket2 0.5.10", + "socket2 0.6.4", "thiserror 2.0.18", "tokio", "tracing", @@ -7505,9 +7851,9 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.5.10", + "socket2 0.6.4", "tracing", - "windows-sys 0.60.2", + "windows-sys 0.59.0", ] [[package]] @@ -7743,7 +8089,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", ] [[package]] @@ -7814,17 +8160,21 @@ checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" dependencies = [ "base64", "bytes", + "encoding_rs", "futures-core", "futures-util", "h2", - "http 1.4.0", + "http 1.4.1", "http-body", "http-body-util", "hyper", "hyper-rustls", + "hyper-tls", "hyper-util", "js-sys", "log", + "mime", + "native-tls", "percent-encoding", "pin-project-lite", "quinn", @@ -7835,6 +8185,7 @@ dependencies = [ "serde_urlencoded", "sync_wrapper", "tokio", + "tokio-native-tls", "tokio-rustls", "tokio-util", "tower", @@ -7953,7 +8304,7 @@ dependencies = [ "anyhow", "bytemuck", "cfg-if", - "keccak", + "keccak 0.1.6", "liblzma", "paste", "rayon", @@ -8136,7 +8487,7 @@ dependencies = [ "borsh", "bytemuck", "cfg-if", - "digest", + "digest 0.10.7", "ff", "hex", "hex-literal 0.4.1", @@ -8175,7 +8526,7 @@ dependencies = [ "gdbstub_arch", "gimli", "hex", - "keccak", + "keccak 0.1.6", "lazy-regex", "num-bigint 0.4.6", "num-traits", @@ -8239,9 +8590,9 @@ checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746" [[package]] name = "rpassword" -version = "7.5.2" +version = "7.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ac5b223d9738ef56e0b98305410be40fa0941bf6036c56f1506751e43552d64" +checksum = "2da316a15f47e3d053de9cb2c439650bd8fa4aaeb9365f2e5f27f492ff73c196" dependencies = [ "libc", "rtoolbox", @@ -8294,16 +8645,16 @@ version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" dependencies = [ - "const-oid", - "digest", + "const-oid 0.9.6", + "digest 0.10.7", "num-bigint-dig", "num-integer", "num-traits", "pkcs1", - "pkcs8", + "pkcs8 0.10.2", "rand_core 0.6.4", "signature", - "spki", + "spki 0.7.3", "subtle", "zeroize", ] @@ -8353,9 +8704,9 @@ dependencies = [ [[package]] name = "ruint" -version = "1.17.0" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a68df0380e5c9d20ce49534f292a36a7514ae21350726efe1865bdb1fa91d278" +checksum = "c141e807189ad38a07276942c6623032d3753c8859c146104ac2e4d68865945a" dependencies = [ "borsh", "proptest", @@ -8409,11 +8760,11 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "errno", "libc", "linux-raw-sys", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -8433,9 +8784,9 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d" dependencies = [ "openssl-probe", "rustls-pki-types", @@ -8471,7 +8822,7 @@ dependencies = [ "security-framework", "security-framework-sys", "webpki-root-certs 0.26.11", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -8619,9 +8970,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", - "der", + "der 0.7.10", "generic-array 0.14.7", - "pkcs8", + "pkcs8 0.10.2", "serdect", "subtle", "zeroize", @@ -8633,7 +8984,7 @@ version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "core-foundation 0.10.1", "core-foundation-sys", "libc", @@ -8675,20 +9026,23 @@ version = "0.1.0" dependencies = [ "anyhow", "borsh", + "bridge_core", "bytesize", "chrono", "common", "faucet_core", "futures", + "hex", "humantime-serde", + "lee", + "lee_core", "log", "logos-blockchain-core", "logos-blockchain-key-management-system-service", "logos-blockchain-zone-sdk", "mempool", - "nssa", - "nssa_core", "rand 0.8.6", + "risc0-zkvm", "serde", "serde_json", "storage", @@ -8712,9 +9066,9 @@ dependencies = [ "env_logger", "futures", "jsonrpsee", + "lee", "log", "mempool", - "nssa", "sequencer_core", "sequencer_service_protocol", "sequencer_service_rpc", @@ -8727,8 +9081,8 @@ name = "sequencer_service_protocol" version = "0.1.0" dependencies = [ "common", - "nssa", - "nssa_core", + "lee", + "lee_core", ] [[package]] @@ -8942,7 +9296,7 @@ dependencies = [ "const_format", "futures", "gloo-net", - "http 1.4.0", + "http 1.4.1", "http-body-util", "hyper", "inventory", @@ -9002,7 +9356,7 @@ checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures 0.2.17", - "digest", + "digest 0.10.7", ] [[package]] @@ -9013,7 +9367,17 @@ checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures 0.2.17", - "digest", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be176f1a57ce4e3d31c1a166222d9768de5954f811601fb7ca06fc8203905ce1" +dependencies = [ + "digest 0.11.3", + "keccak 0.2.0", ] [[package]] @@ -9031,6 +9395,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + [[package]] name = "signal-hook-registry" version = "1.4.8" @@ -9047,7 +9417,7 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "digest", + "digest 0.10.7", "rand_core 0.6.4", ] @@ -9106,9 +9476,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" dependencies = [ "libc", "windows-sys 0.61.2", @@ -9123,7 +9493,7 @@ dependencies = [ "base64", "bytes", "futures", - "http 1.4.0", + "http 1.4.1", "httparse", "log", "rand 0.8.6", @@ -9146,7 +9516,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", - "der", + "der 0.7.10", +] + +[[package]] +name = "spki" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d9efca8738c78ee9484207732f728b1ef517bbb1833d6fc0879ca898a522f6f" +dependencies = [ + "base64ct", + "der 0.8.0", ] [[package]] @@ -9177,7 +9557,7 @@ version = "0.1.0" dependencies = [ "borsh", "common", - "nssa", + "lee", "rocksdb", "tempfile", "thiserror 2.0.18", @@ -9305,7 +9685,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "core-foundation 0.9.4", "system-configuration-sys", ] @@ -9316,7 +9696,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "core-foundation 0.9.4", "system-configuration-sys", ] @@ -9375,6 +9755,17 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "tar" +version = "0.4.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840" +dependencies = [ + "filetime", + "libc", + "xattr", +] + [[package]] name = "target-lexicon" version = "0.13.5" @@ -9391,7 +9782,7 @@ dependencies = [ "getrandom 0.4.2", "once_cell", "rustix", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -9439,9 +9830,9 @@ dependencies = [ "indexer_service", "jsonrpsee", "key_protocol", + "lee", + "lee_core", "log", - "nssa", - "nssa_core", "sequencer_core", "sequencer_service", "sequencer_service_rpc", @@ -9469,7 +9860,7 @@ dependencies = [ "authenticated_transfer_core", "clock_core", "faucet_core", - "nssa_core", + "lee_core", "risc0-zkvm", "serde", ] @@ -9490,7 +9881,7 @@ dependencies = [ "etcetera", "ferroid", "futures", - "http 1.4.0", + "http 1.4.1", "itertools 0.14.0", "log", "memchr", @@ -9513,8 +9904,8 @@ version = "0.1.0" dependencies = [ "common", "key_protocol", - "nssa", - "nssa_core", + "lee", + "lee_core", "serde", ] @@ -9656,7 +10047,7 @@ name = "token_core" version = "0.1.0" dependencies = [ "borsh", - "nssa_core", + "lee_core", "serde", ] @@ -9664,7 +10055,7 @@ dependencies = [ name = "token_program" version = "0.1.0" dependencies = [ - "nssa_core", + "lee_core", "token_core", ] @@ -9680,7 +10071,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.3", + "socket2 0.6.4", "tokio-macros", "windows-sys 0.61.2", ] @@ -9696,6 +10087,16 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.26.4" @@ -9827,9 +10228,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.25.11+spec-1.1.0" +version = "0.25.12+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b" +checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7" dependencies = [ "indexmap 2.14.0", "toml_datetime 1.1.1+spec-1.1.0", @@ -9869,7 +10270,7 @@ dependencies = [ "base64", "bytes", "h2", - "http 1.4.0", + "http 1.4.1", "http-body", "http-body-util", "hyper", @@ -9877,7 +10278,7 @@ dependencies = [ "hyper-util", "percent-encoding", "pin-project", - "socket2 0.6.3", + "socket2 0.6.4", "sync_wrapper", "tokio", "tokio-stream", @@ -9923,11 +10324,11 @@ version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "bytes", "futures-core", "futures-util", - "http 1.4.0", + "http 1.4.1", "http-body", "http-body-util", "http-range-header", @@ -10134,7 +10535,7 @@ checksum = "6c01152af293afb9c7c2a57e4b559c5620b421f6d133261c60dd2d0cdb38e6b8" dependencies = [ "bytes", "data-encoding", - "http 1.4.0", + "http 1.4.1", "httparse", "log", "rand 0.9.4", @@ -10186,9 +10587,9 @@ checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" [[package]] name = "typenum" -version = "1.20.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" [[package]] name = "typetag" @@ -10255,9 +10656,9 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.13.2" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" [[package]] name = "unicode-width" @@ -10324,12 +10725,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dea7109cdcd5864d4eeb1b58a1648dc9bf520360d7af16ec26d0a9354bafcfc0" dependencies = [ "base64", + "flate2", "log", "percent-encoding", "rustls", "rustls-pki-types", "ureq-proto", "utf8-zero", + "webpki-roots", ] [[package]] @@ -10339,7 +10742,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e994ba84b0bd1b1b0cf92878b7ef898a5c1760108fe7b6010327e274917a808c" dependencies = [ "base64", - "http 1.4.0", + "http 1.4.1", "httparse", "log", ] @@ -10388,16 +10791,70 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] -name = "uuid" -version = "1.23.1" +name = "utoipa" +version = "4.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" +checksum = "c5afb1a60e207dca502682537fefcfd9921e71d0b83e9576060f09abc6efab23" +dependencies = [ + "indexmap 2.14.0", + "serde", + "serde_json", + "utoipa-gen", +] + +[[package]] +name = "utoipa-gen" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20c24e8ab68ff9ee746aad22d39b5535601e6416d1b0feeabf78be986a5c4392" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "uuid" +version = "1.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d258b83ceec21034727ecee8c382cfa6c3e133699b0742c64571814fb420c9f7" dependencies = [ "getrandom 0.4.2", "js-sys", "wasm-bindgen", ] +[[package]] +name = "validator" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43fb22e1a008ece370ce08a3e9e4447a910e92621bb49b85d6e48a45397e7cfa" +dependencies = [ + "idna", + "once_cell", + "regex", + "serde", + "serde_derive", + "serde_json", + "url", + "validator_derive", +] + +[[package]] +name = "validator_derive" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7df16e474ef958526d1205f6dda359fdfab79d9aa6d54bafcb92dcd07673dca" +dependencies = [ + "darling 0.20.11", + "once_cell", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "valuable" version = "0.1.1" @@ -10408,7 +10865,7 @@ checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" name = "vault_core" version = "0.1.0" dependencies = [ - "nssa_core", + "lee_core", "risc0-zkvm", "serde", ] @@ -10459,9 +10916,9 @@ dependencies = [ "itertools 0.14.0", "key_protocol", "keycard_wallet", + "lee", + "lee_core", "log", - "nssa", - "nssa_core", "optfield", "pyo3", "rand 0.8.6", @@ -10485,8 +10942,8 @@ version = "0.1.0" dependencies = [ "cbindgen", "key_protocol", - "nssa", - "nssa_core", + "lee", + "lee_core", "sequencer_service_rpc", "serde_json", "tempfile", @@ -10529,9 +10986,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.121" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790" +checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409" dependencies = [ "cfg-if", "once_cell", @@ -10542,9 +10999,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.71" +version = "0.4.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96492d0d3ffba25305a7dc88720d250b1401d7edca02cc3bcd50633b424673b8" +checksum = "9473dbd2991ae90b6291c3c32c30c6187ac49aa32f9905d1cce280ec1e110b0f" dependencies = [ "js-sys", "wasm-bindgen", @@ -10552,9 +11009,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.121" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578" +checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -10562,9 +11019,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.121" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2" +checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e" dependencies = [ "bumpalo", "proc-macro2", @@ -10575,9 +11032,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.121" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441" +checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437" dependencies = [ "unicode-ident", ] @@ -10658,7 +11115,7 @@ version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "hashbrown 0.15.5", "indexmap 2.14.0", "semver", @@ -10666,9 +11123,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.98" +version = "0.3.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b572dff8bcf38bad0fa19729c89bb5748b2b9b1d8be70cf90df697e3a8f32aa" +checksum = "6d621441cfc37b84979402712047321980c178f299193a3589d05b99e8763436" dependencies = [ "js-sys", "wasm-bindgen", @@ -10749,7 +11206,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -10897,15 +11354,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-sys" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" -dependencies = [ - "windows-targets 0.53.5", -] - [[package]] name = "windows-sys" version = "0.61.2" @@ -10939,30 +11387,13 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", + "windows_i686_gnullvm", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] -[[package]] -name = "windows-targets" -version = "0.53.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" -dependencies = [ - "windows-link", - "windows_aarch64_gnullvm 0.53.1", - "windows_aarch64_msvc 0.53.1", - "windows_i686_gnu 0.53.1", - "windows_i686_gnullvm 0.53.1", - "windows_i686_msvc 0.53.1", - "windows_x86_64_gnu 0.53.1", - "windows_x86_64_gnullvm 0.53.1", - "windows_x86_64_msvc 0.53.1", -] - [[package]] name = "windows-threading" version = "0.2.1" @@ -10984,12 +11415,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" - [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -11002,12 +11427,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" - [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -11020,24 +11439,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" -[[package]] -name = "windows_i686_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" - [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" - [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -11050,12 +11457,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_i686_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" - [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -11068,12 +11469,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" - [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -11086,12 +11481,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" - [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -11104,12 +11493,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" - [[package]] name = "winnow" version = "0.7.15" @@ -11192,7 +11575,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ "anyhow", - "bitflags 2.11.1", + "bitflags 2.12.1", "indexmap 2.14.0", "log", "serde", @@ -11348,18 +11731,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.48" +version = "0.8.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +checksum = "3b065d4f0e55f82fae73202e189638116a87c55ab6b8e6c2721e13dd9d854ad1" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.48" +version = "0.8.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +checksum = "0b631b19d36a892ab55420c92dbc83ccd79274f25be714855d3074aa71cab639" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index eda859fe..290c3540 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,14 +5,14 @@ license = "MIT or Apache-2.0" resolver = "3" members = [ "integration_tests", - "storage", - "key_protocol", - "mempool", - "wallet", - "wallet-ffi", - "common", - "nssa", - "nssa/core", + "lez/storage", + "lee/key_protocol", + "lee/state_machine", + "lee/state_machine/core", + "lez/mempool", + "lez/wallet", + "lez/wallet-ffi", + "lez/common", "programs/amm/core", "programs/amm", "programs/clock/core", @@ -22,16 +22,17 @@ members = [ "programs/associated_token_account", "programs/authenticated_transfer/core", "programs/faucet/core", + "programs/bridge/core", "programs/vault/core", - "sequencer/core", - "sequencer/service", - "sequencer/service/protocol", - "sequencer/service/rpc", - "indexer/core", - "indexer/service", - "indexer/service/protocol", - "indexer/service/rpc", - "explorer_service", + "lez/sequencer/core", + "lez/sequencer/service", + "lez/sequencer/service/protocol", + "lez/sequencer/service/rpc", + "lez/indexer/core", + "lez/indexer/service", + "lez/indexer/service/protocol", + "lez/indexer/service/rpc", + "lez/explorer_service", "program_methods", "program_methods/guest", "test_program_methods", @@ -39,9 +40,10 @@ members = [ "examples/program_deployment", "examples/program_deployment/methods", "examples/program_deployment/methods/guest", - "testnet_initial_state", - "indexer/ffi", - "keycard_wallet", + "lez/testnet_initial_state", + "lez/indexer/ffi", + "lez", + "lez/keycard_wallet", "test_fixtures", "tools/cycle_bench", "tools/crypto_primitives_bench", @@ -49,23 +51,24 @@ members = [ ] [workspace.dependencies] -nssa = { path = "nssa" } -nssa_core = { path = "nssa/core" } -common = { path = "common" } -mempool = { path = "mempool" } -storage = { path = "storage" } -key_protocol = { path = "key_protocol" } -sequencer_core = { path = "sequencer/core" } -sequencer_service_protocol = { path = "sequencer/service/protocol" } -sequencer_service_rpc = { path = "sequencer/service/rpc" } -sequencer_service = { path = "sequencer/service" } -indexer_core = { path = "indexer/core" } -indexer_service = { path = "indexer/service" } -indexer_service_protocol = { path = "indexer/service/protocol" } -indexer_service_rpc = { path = "indexer/service/rpc" } -wallet = { path = "wallet" } -wallet-ffi = { path = "wallet-ffi", default-features = false } -indexer_ffi = { path = "indexer/ffi" } +lee = { path = "lee/state_machine" } +lee_core = { path = "lee/state_machine/core" } +common = { path = "lez/common" } +mempool = { path = "lez/mempool" } +storage = { path = "lez/storage" } +key_protocol = { path = "lee/key_protocol" } +sequencer_core = { path = "lez/sequencer/core" } +sequencer_service_protocol = { path = "lez/sequencer/service/protocol" } +sequencer_service_rpc = { path = "lez/sequencer/service/rpc" } +sequencer_service = { path = "lez/sequencer/service" } +indexer_core = { path = "lez/indexer/core" } +indexer_service = { path = "lez/indexer/service" } +indexer_service_protocol = { path = "lez/indexer/service/protocol" } +indexer_service_rpc = { path = "lez/indexer/service/rpc" } +wallet = { path = "lez/wallet" } +wallet-ffi = { path = "lez/wallet-ffi", default-features = false } +indexer_ffi = { path = "lez/indexer/ffi" } +lez = { path = "lez" } clock_core = { path = "programs/clock/core" } token_core = { path = "programs/token/core" } token_program = { path = "programs/token" } @@ -75,10 +78,11 @@ ata_core = { path = "programs/associated_token_account/core" } ata_program = { path = "programs/associated_token_account" } authenticated_transfer_core = { path = "programs/authenticated_transfer/core" } faucet_core = { path = "programs/faucet/core" } +bridge_core = { path = "programs/bridge/core" } vault_core = { path = "programs/vault/core" } test_program_methods = { path = "test_program_methods" } -testnet_initial_state = { path = "testnet_initial_state" } -keycard_wallet = { path = "keycard_wallet" } +testnet_initial_state = { path = "lez/testnet_initial_state" } +keycard_wallet = { path = "lez/keycard_wallet" } test_fixtures = { path = "test_fixtures" } tokio = { version = "1.50", features = [ @@ -134,12 +138,13 @@ tokio-retry = "0.3.0" schemars = "1.2" async-stream = "0.3.6" -logos-blockchain-common-http-client = { git = "https://github.com/logos-blockchain/logos-blockchain.git", rev = "ee281a447d95a951752461ee0a6e88eb4a0f17cf" } -logos-blockchain-key-management-system-service = { git = "https://github.com/logos-blockchain/logos-blockchain.git", rev = "ee281a447d95a951752461ee0a6e88eb4a0f17cf" } -logos-blockchain-core = { git = "https://github.com/logos-blockchain/logos-blockchain.git", rev = "ee281a447d95a951752461ee0a6e88eb4a0f17cf" } -logos-blockchain-chain-broadcast-service = { git = "https://github.com/logos-blockchain/logos-blockchain.git", rev = "ee281a447d95a951752461ee0a6e88eb4a0f17cf" } -logos-blockchain-chain-service = { git = "https://github.com/logos-blockchain/logos-blockchain.git", rev = "ee281a447d95a951752461ee0a6e88eb4a0f17cf" } -logos-blockchain-zone-sdk = { git = "https://github.com/logos-blockchain/logos-blockchain.git", rev = "ee281a447d95a951752461ee0a6e88eb4a0f17cf" } +logos-blockchain-common-http-client = { git = "https://github.com/logos-blockchain/logos-blockchain.git", rev = "db9a8d821c1b20f29b03d02072817150cf969b8e" } +logos-blockchain-key-management-system-service = { git = "https://github.com/logos-blockchain/logos-blockchain.git", rev = "db9a8d821c1b20f29b03d02072817150cf969b8e" } +logos-blockchain-core = { git = "https://github.com/logos-blockchain/logos-blockchain.git", rev = "db9a8d821c1b20f29b03d02072817150cf969b8e" } +logos-blockchain-chain-broadcast-service = { git = "https://github.com/logos-blockchain/logos-blockchain.git", rev = "db9a8d821c1b20f29b03d02072817150cf969b8e" } +logos-blockchain-chain-service = { git = "https://github.com/logos-blockchain/logos-blockchain.git", rev = "db9a8d821c1b20f29b03d02072817150cf969b8e" } +logos-blockchain-zone-sdk = { git = "https://github.com/logos-blockchain/logos-blockchain.git", rev = "db9a8d821c1b20f29b03d02072817150cf969b8e" } +logos-blockchain-http-api-common = { git = "https://github.com/logos-blockchain/logos-blockchain.git", rev = "db9a8d821c1b20f29b03d02072817150cf969b8e" } rocksdb = { version = "0.24.0", default-features = false, features = [ "snappy", @@ -153,6 +158,7 @@ k256 = { version = "0.13.3", features = [ "serde", "pem", ] } +ml-kem = { version = "0.3", features = ["hazmat"] } elliptic-curve = { version = "0.13.8", features = ["arithmetic"] } actix-web = { version = "4.13.0", default-features = false, features = [ "macros", diff --git a/Justfile b/Justfile index 7af964a6..83c9dd0c 100644 --- a/Justfile +++ b/Justfile @@ -36,13 +36,13 @@ run-bedrock: docker compose up # Run Sequencer -[working-directory: 'sequencer/service'] +[working-directory: 'lez/sequencer/service'] run-sequencer: @echo "🧠 Running sequencer" RUST_LOG=info RISC0_DEV_MODE=1 cargo run --release -p sequencer_service configs/debug/sequencer_config.json # Run Indexer -[working-directory: 'indexer/service'] +[working-directory: 'lez/indexer/service'] run-indexer mock="": @echo "🔍 Running indexer" @if [ "{{mock}}" = "mock" ]; then \ @@ -54,23 +54,23 @@ run-indexer mock="": fi # Run Explorer -[working-directory: 'explorer_service'] +[working-directory: 'lez/explorer_service'] run-explorer: @echo "🌐 Running explorer" RUST_LOG=info cargo leptos serve # Run Wallet -[working-directory: 'wallet'] +[working-directory: 'lez/wallet'] run-wallet +args: @echo "🔑 Running wallet" - NSSA_WALLET_HOME_DIR=$(pwd)/configs/debug cargo run --release -p wallet -- {{args}} + LEE_WALLET_HOME_DIR=$(pwd)/configs/debug cargo run --release -p wallet -- {{args}} # Clean runtime data clean: @echo "🧹 Cleaning run artifacts" - rm -rf sequencer/service/bedrock_signing_key - rm -rf sequencer/service/rocksdb - rm -rf indexer/service/rocksdb - rm -rf wallet/configs/debug/storage.json + rm -rf lez/sequencer/service/bedrock_signing_key + rm -rf lez/sequencer/service/rocksdb + rm -rf lez/indexer/service/rocksdb + rm -rf lez/wallet/configs/debug/storage.json rm -rf rocksdb cd bedrock && docker compose down -v diff --git a/README.md b/README.md index a08b81fb..f1ae82dc 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ For each tag we publish docker images of our services. If you depend on this project you can pin your rust dependency to a git tag like this: ```toml -nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.1.0" } +lee_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.1.0" } ``` # Install dependencies @@ -134,7 +134,7 @@ RISC0_DEV_MODE=1 cargo test --release ### Integration tests ```bash -export NSSA_WALLET_HOME_DIR=$(pwd)/integration_tests/configs/debug/wallet/ +export LEE_WALLET_HOME_DIR=$(pwd)/integration_tests/configs/debug/wallet/ cd integration_tests # RISC0_DEV_MODE=1 skips proof generation; RUST_LOG=info enables runtime logs RUST_LOG=info RISC0_DEV_MODE=1 cargo run $(pwd)/configs/debug all @@ -152,17 +152,17 @@ The sequencer and logos blockchain node can be run locally: - `cargo build --all-features` - `./target/debug/logos-blockchain-node --deployment nodes/node/standalone-deployment-config.yaml nodes/node/standalone-node-config.yaml` - - Alternatively (WARNING: This node is outdated) go to `logos-blockchain/lssa/` repo and run the node from docker: + - Alternatively (WARNING: This node is outdated) go to `logos-blockchain/logos-execution-zone/` repo and run the node from docker: - `cd bedrock` - Change line 14 of `docker-compose.yml` from `"0:18080/tcp"` into `"8080:18080/tcp"` - `docker compose up` - 2. On another terminal go to the `logos-blockchain/lssa` repo and run indexer service: - - `RUST_LOG=info cargo run -p indexer_service indexer/service/configs/indexer_config.json` + 2. On another terminal go to the `logos-blockchain/logos-execution-zone` repo and run indexer service: + - `RUST_LOG=info cargo run -p indexer_service lez/indexer/service/configs/indexer_config.json` - 3. On another terminal go to the `logos-blockchain/lssa` repo and run the sequencer: - - `RUST_LOG=info cargo run -p sequencer_service sequencer/service/configs/debug/sequencer_config.json` - 4. (To run the explorer): on another terminal go to `logos-blockchain/lssa/explorer_service` and run the following: + 3. On another terminal go to the `logos-blockchain/logos-execution-zone` repo and run the sequencer: + - `RUST_LOG=info cargo run -p sequencer_service lez/sequencer/service/configs/debug/sequencer_config.json` + 4. (To run the explorer): on another terminal go to `logos-blockchain/logos-execution-zone/lez/explorer_service` and run the following: - `cargo install cargo-leptos` - `cargo leptos build --release` - `cargo leptos serve --release` @@ -171,9 +171,9 @@ The sequencer and logos blockchain node can be run locally: After stopping services above you need to remove 3 folders to start cleanly: 1. In the `logos-blockchain/logos-blockchain` folder `state` (not needed in case of docker setup) - 2. In the `lssa` folder `sequencer/service/rocksdb` - 3. In the `lssa` file `sequencer/service/bedrock_signing_key` - 4. In the `lssa` folder `indexer/service/rocksdb` + 2. In the `logos-execution-zone` folder `lez/sequencer/service/rocksdb` + 3. In the `logos-execution-zone` file `lez/sequencer/service/bedrock_signing_key` + 4. In the `logos-execution-zone` folder `lez/indexer/service/rocksdb` ### Normal mode (`just` commands) We provide a `Justfile` for developer and user needs, you can run the whole setup with it. The only difference will be that logos-blockchain (bedrock) will be started from docker. @@ -220,7 +220,7 @@ This will use a wallet binary built from this repo and not the one installed in ### Standalone mode The sequencer can be run in standalone mode with: ```bash -RUST_LOG=info cargo run --features standalone -p sequencer_service sequencer/service/configs/debug +RUST_LOG=info cargo run --features standalone -p sequencer_service lez/sequencer/service/configs/debug ``` ## Running with Docker @@ -231,7 +231,7 @@ You can run the whole setup with Docker: docker compose up ``` -With that you can send transactions from local wallet to the Sequencer running inside Docker using `wallet/configs/debug` as well as exploring blocks by opening `http://localhost:8080`. +With that you can send transactions from local wallet to the Sequencer running inside Docker using `lez/wallet/configs/debug` as well as exploring blocks by opening `http://localhost:8080`. ## Caution for local image builds diff --git a/artifacts/program_methods/amm.bin b/artifacts/program_methods/amm.bin index 52067453..046f21bb 100644 Binary files a/artifacts/program_methods/amm.bin and b/artifacts/program_methods/amm.bin differ diff --git a/artifacts/program_methods/associated_token_account.bin b/artifacts/program_methods/associated_token_account.bin index 339f634c..cae6ed4e 100644 Binary files a/artifacts/program_methods/associated_token_account.bin and b/artifacts/program_methods/associated_token_account.bin differ diff --git a/artifacts/program_methods/authenticated_transfer.bin b/artifacts/program_methods/authenticated_transfer.bin index ae1dc1aa..cebe1042 100644 Binary files a/artifacts/program_methods/authenticated_transfer.bin and b/artifacts/program_methods/authenticated_transfer.bin differ diff --git a/artifacts/program_methods/bridge.bin b/artifacts/program_methods/bridge.bin index 58a6cf32..9810c6ac 100644 Binary files a/artifacts/program_methods/bridge.bin and b/artifacts/program_methods/bridge.bin differ diff --git a/artifacts/program_methods/clock.bin b/artifacts/program_methods/clock.bin index aaca2737..1124913f 100644 Binary files a/artifacts/program_methods/clock.bin and b/artifacts/program_methods/clock.bin differ diff --git a/artifacts/program_methods/faucet.bin b/artifacts/program_methods/faucet.bin index 8b3bda76..ca45b686 100644 Binary files a/artifacts/program_methods/faucet.bin and b/artifacts/program_methods/faucet.bin differ diff --git a/artifacts/program_methods/pinata.bin b/artifacts/program_methods/pinata.bin index fad19f0b..118f19d3 100644 Binary files a/artifacts/program_methods/pinata.bin and b/artifacts/program_methods/pinata.bin differ diff --git a/artifacts/program_methods/pinata_token.bin b/artifacts/program_methods/pinata_token.bin index bd38db1a..f3ecb0e9 100644 Binary files a/artifacts/program_methods/pinata_token.bin and b/artifacts/program_methods/pinata_token.bin differ diff --git a/artifacts/program_methods/privacy_preserving_circuit.bin b/artifacts/program_methods/privacy_preserving_circuit.bin index f8df6383..66f6d5b6 100644 Binary files a/artifacts/program_methods/privacy_preserving_circuit.bin and b/artifacts/program_methods/privacy_preserving_circuit.bin differ diff --git a/artifacts/program_methods/token.bin b/artifacts/program_methods/token.bin index ba54f9f3..a36fbbc8 100644 Binary files a/artifacts/program_methods/token.bin and b/artifacts/program_methods/token.bin differ diff --git a/artifacts/program_methods/vault.bin b/artifacts/program_methods/vault.bin index 1d853c3c..7628b459 100644 Binary files a/artifacts/program_methods/vault.bin and b/artifacts/program_methods/vault.bin differ diff --git a/artifacts/test_program_methods/auth_asserting_noop.bin b/artifacts/test_program_methods/auth_asserting_noop.bin index 720f8ea6..3884195d 100644 Binary files a/artifacts/test_program_methods/auth_asserting_noop.bin and b/artifacts/test_program_methods/auth_asserting_noop.bin differ diff --git a/artifacts/test_program_methods/auth_transfer_proxy.bin b/artifacts/test_program_methods/auth_transfer_proxy.bin index f79510cf..6afda3a5 100644 Binary files a/artifacts/test_program_methods/auth_transfer_proxy.bin and b/artifacts/test_program_methods/auth_transfer_proxy.bin differ diff --git a/artifacts/test_program_methods/burner.bin b/artifacts/test_program_methods/burner.bin index d5c2611b..dd2db03f 100644 Binary files a/artifacts/test_program_methods/burner.bin and b/artifacts/test_program_methods/burner.bin differ diff --git a/artifacts/test_program_methods/chain_caller.bin b/artifacts/test_program_methods/chain_caller.bin index edc15959..58291896 100644 Binary files a/artifacts/test_program_methods/chain_caller.bin and b/artifacts/test_program_methods/chain_caller.bin differ diff --git a/artifacts/test_program_methods/changer_claimer.bin b/artifacts/test_program_methods/changer_claimer.bin index 8871ce27..bb2feabb 100644 Binary files a/artifacts/test_program_methods/changer_claimer.bin and b/artifacts/test_program_methods/changer_claimer.bin differ diff --git a/artifacts/test_program_methods/claimer.bin b/artifacts/test_program_methods/claimer.bin index 2ca68617..b0f3a67c 100644 Binary files a/artifacts/test_program_methods/claimer.bin and b/artifacts/test_program_methods/claimer.bin differ diff --git a/artifacts/test_program_methods/clock_chain_caller.bin b/artifacts/test_program_methods/clock_chain_caller.bin index b46141ce..5cda6717 100644 Binary files a/artifacts/test_program_methods/clock_chain_caller.bin and b/artifacts/test_program_methods/clock_chain_caller.bin differ diff --git a/artifacts/test_program_methods/data_changer.bin b/artifacts/test_program_methods/data_changer.bin index 4685608a..898cea24 100644 Binary files a/artifacts/test_program_methods/data_changer.bin and b/artifacts/test_program_methods/data_changer.bin differ diff --git a/artifacts/test_program_methods/extra_output.bin b/artifacts/test_program_methods/extra_output.bin index 3221ba35..a74d931d 100644 Binary files a/artifacts/test_program_methods/extra_output.bin and b/artifacts/test_program_methods/extra_output.bin differ diff --git a/artifacts/test_program_methods/faucet_chain_caller.bin b/artifacts/test_program_methods/faucet_chain_caller.bin index 81aa21f6..8effbf85 100644 Binary files a/artifacts/test_program_methods/faucet_chain_caller.bin and b/artifacts/test_program_methods/faucet_chain_caller.bin differ diff --git a/artifacts/test_program_methods/flash_swap_callback.bin b/artifacts/test_program_methods/flash_swap_callback.bin index 513e7856..e4aa09dc 100644 Binary files a/artifacts/test_program_methods/flash_swap_callback.bin and b/artifacts/test_program_methods/flash_swap_callback.bin differ diff --git a/artifacts/test_program_methods/flash_swap_initiator.bin b/artifacts/test_program_methods/flash_swap_initiator.bin index 3740635d..f0d031b8 100644 Binary files a/artifacts/test_program_methods/flash_swap_initiator.bin and b/artifacts/test_program_methods/flash_swap_initiator.bin differ diff --git a/artifacts/test_program_methods/malicious_authorization_changer.bin b/artifacts/test_program_methods/malicious_authorization_changer.bin index b34e6398..589bc620 100644 Binary files a/artifacts/test_program_methods/malicious_authorization_changer.bin and b/artifacts/test_program_methods/malicious_authorization_changer.bin differ diff --git a/artifacts/test_program_methods/malicious_caller_program_id.bin b/artifacts/test_program_methods/malicious_caller_program_id.bin index c1f65dce..8c0d1350 100644 Binary files a/artifacts/test_program_methods/malicious_caller_program_id.bin and b/artifacts/test_program_methods/malicious_caller_program_id.bin differ diff --git a/artifacts/test_program_methods/malicious_injector.bin b/artifacts/test_program_methods/malicious_injector.bin index 8c2acf82..8bcccb4e 100644 Binary files a/artifacts/test_program_methods/malicious_injector.bin and b/artifacts/test_program_methods/malicious_injector.bin differ diff --git a/artifacts/test_program_methods/malicious_launderer.bin b/artifacts/test_program_methods/malicious_launderer.bin index 547a21a2..70392d9c 100644 Binary files a/artifacts/test_program_methods/malicious_launderer.bin and b/artifacts/test_program_methods/malicious_launderer.bin differ diff --git a/artifacts/test_program_methods/malicious_self_program_id.bin b/artifacts/test_program_methods/malicious_self_program_id.bin index 3a291460..62b8af74 100644 Binary files a/artifacts/test_program_methods/malicious_self_program_id.bin and b/artifacts/test_program_methods/malicious_self_program_id.bin differ diff --git a/artifacts/test_program_methods/minter.bin b/artifacts/test_program_methods/minter.bin index a27b7a4e..c4b115ab 100644 Binary files a/artifacts/test_program_methods/minter.bin and b/artifacts/test_program_methods/minter.bin differ diff --git a/artifacts/test_program_methods/missing_output.bin b/artifacts/test_program_methods/missing_output.bin index 505322a6..ae599f60 100644 Binary files a/artifacts/test_program_methods/missing_output.bin and b/artifacts/test_program_methods/missing_output.bin differ diff --git a/artifacts/test_program_methods/modified_transfer.bin b/artifacts/test_program_methods/modified_transfer.bin index aaa5dcb0..1435dea9 100644 Binary files a/artifacts/test_program_methods/modified_transfer.bin and b/artifacts/test_program_methods/modified_transfer.bin differ diff --git a/artifacts/test_program_methods/nonce_changer.bin b/artifacts/test_program_methods/nonce_changer.bin index 8dc636da..bc479a80 100644 Binary files a/artifacts/test_program_methods/nonce_changer.bin and b/artifacts/test_program_methods/nonce_changer.bin differ diff --git a/artifacts/test_program_methods/noop.bin b/artifacts/test_program_methods/noop.bin index 69e69635..e0d52639 100644 Binary files a/artifacts/test_program_methods/noop.bin and b/artifacts/test_program_methods/noop.bin differ diff --git a/artifacts/test_program_methods/pda_claimer.bin b/artifacts/test_program_methods/pda_claimer.bin index f5603d58..f34373ff 100644 Binary files a/artifacts/test_program_methods/pda_claimer.bin and b/artifacts/test_program_methods/pda_claimer.bin differ diff --git a/artifacts/test_program_methods/pda_spend_proxy.bin b/artifacts/test_program_methods/pda_spend_proxy.bin index 9f0d0c3e..33e38f00 100644 Binary files a/artifacts/test_program_methods/pda_spend_proxy.bin and b/artifacts/test_program_methods/pda_spend_proxy.bin differ diff --git a/artifacts/test_program_methods/pinata_cooldown.bin b/artifacts/test_program_methods/pinata_cooldown.bin index a2194ba1..65879893 100644 Binary files a/artifacts/test_program_methods/pinata_cooldown.bin and b/artifacts/test_program_methods/pinata_cooldown.bin differ diff --git a/artifacts/test_program_methods/private_pda_delegator.bin b/artifacts/test_program_methods/private_pda_delegator.bin index 9fcb05cf..7652eaa7 100644 Binary files a/artifacts/test_program_methods/private_pda_delegator.bin and b/artifacts/test_program_methods/private_pda_delegator.bin differ diff --git a/artifacts/test_program_methods/program_owner_changer.bin b/artifacts/test_program_methods/program_owner_changer.bin index 92749650..81d9a7e1 100644 Binary files a/artifacts/test_program_methods/program_owner_changer.bin and b/artifacts/test_program_methods/program_owner_changer.bin differ diff --git a/artifacts/test_program_methods/simple_balance_transfer.bin b/artifacts/test_program_methods/simple_balance_transfer.bin index 78a75df9..ef9b3006 100644 Binary files a/artifacts/test_program_methods/simple_balance_transfer.bin and b/artifacts/test_program_methods/simple_balance_transfer.bin differ diff --git a/artifacts/test_program_methods/time_locked_transfer.bin b/artifacts/test_program_methods/time_locked_transfer.bin index 296863e9..ba50eebd 100644 Binary files a/artifacts/test_program_methods/time_locked_transfer.bin and b/artifacts/test_program_methods/time_locked_transfer.bin differ diff --git a/artifacts/test_program_methods/two_pda_claimer.bin b/artifacts/test_program_methods/two_pda_claimer.bin index 34c8f27c..32a8b581 100644 Binary files a/artifacts/test_program_methods/two_pda_claimer.bin and b/artifacts/test_program_methods/two_pda_claimer.bin differ diff --git a/artifacts/test_program_methods/validity_window.bin b/artifacts/test_program_methods/validity_window.bin index ad2df7c1..85a38041 100644 Binary files a/artifacts/test_program_methods/validity_window.bin and b/artifacts/test_program_methods/validity_window.bin differ diff --git a/artifacts/test_program_methods/validity_window_chain_caller.bin b/artifacts/test_program_methods/validity_window_chain_caller.bin index 4eef9a03..99f379c5 100644 Binary files a/artifacts/test_program_methods/validity_window_chain_caller.bin and b/artifacts/test_program_methods/validity_window_chain_caller.bin differ diff --git a/bedrock/deployment-settings.yaml b/bedrock/deployment-settings.yaml index 7ef63f03..de58f12a 100644 --- a/bedrock/deployment-settings.yaml +++ b/bedrock/deployment-settings.yaml @@ -67,7 +67,9 @@ cryptarchia: - opcode: 17 payload: channel_id: '0000000000000000000000000000000000000000000000000000000000000000' - inscription: '67656e65736973' + # chain_id_len=12 (u64_le), chain_id=logos-devnet (utf-8), + # genesis_time=2026-01-10T07:47:56Z (u64_le), epoch_nonce=[0u8; 32] + inscription: '0c000000000000006c6f676f732d6465766e65742c046269000000000000000000000000000000000000000000000000000000000000000000000000' parent: '0000000000000000000000000000000000000000000000000000000000000000' signer: '0000000000000000000000000000000000000000000000000000000000000000' execution_gas_price: 0 diff --git a/bedrock/docker-compose.yml b/bedrock/docker-compose.yml index e16e505b..356c6df8 100644 --- a/bedrock/docker-compose.yml +++ b/bedrock/docker-compose.yml @@ -1,7 +1,7 @@ services: logos-blockchain-node-0: - image: ghcr.io/logos-blockchain/logos-blockchain@sha256:9f1829dea335c56f6ff68ae37ea872ed5313b96b69e8ffe143c02b7217de85fc + image: ghcr.io/logos-blockchain/logos-blockchain@sha256:f160cfbf898a06554451cc066d84cfd0f8ab62d59bd3e62d9cde3bd5582c12ab ports: - "${PORT:-8080}:18080/tcp" volumes: diff --git a/completions/README.md b/completions/README.md index b12f1823..297b9570 100644 --- a/completions/README.md +++ b/completions/README.md @@ -1,6 +1,6 @@ # Wallet CLI Completion -Completion scripts for the LSSA `wallet` command. +Completion scripts for the LEZ `wallet` command. ## ZSH diff --git a/docker-compose.override.yml b/docker-compose.override.yml index db955b23..a7fddca6 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -12,13 +12,13 @@ services: - logos-blockchain-node-0 - indexer_service volumes: - - ./configs/docker-all-in-one/sequencer_config.json:/etc/sequencer_service/sequencer_config.json + - ./lez/configs/docker-all-in-one/sequencer_config.json:/etc/sequencer_service/sequencer_config.json indexer_service: depends_on: - logos-blockchain-node-0 volumes: - - ./configs/docker-all-in-one/indexer_config.json:/etc/indexer_service/indexer_config.json + - ./lez/configs/docker-all-in-one/indexer_config.json:/etc/indexer_service/indexer_config.json explorer_service: depends_on: diff --git a/docker-compose.yml b/docker-compose.yml index 4fd3910f..3644b2aa 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,8 +6,8 @@ include: - path: bedrock/docker-compose.yml - path: - sequencer/service/docker-compose.yml + lez/sequencer/service/docker-compose.yml - path: - indexer/service/docker-compose.yml + lez/indexer/service/docker-compose.yml - path: - explorer_service/docker-compose.yml + lez/explorer_service/docker-compose.yml diff --git a/docs/LEZ testnet v0.1 tutorials/keycard.md b/docs/LEZ testnet v0.1 tutorials/keycard.md index c01574b4..ab42a8bd 100644 --- a/docs/LEZ testnet v0.1 tutorials/keycard.md +++ b/docs/LEZ testnet v0.1 tutorials/keycard.md @@ -16,28 +16,28 @@ Installation: 1. Install math applet on your keycard; this process only needs to be done once. In the root of repo: ``` sudo apt-get install -y default-jdk - wget https://github.com/martinpaljak/GlobalPlatformPro/releases/download/v25.10.20/gp.jar -P keycard_wallet/keycard_applets - cd keycard_wallet/keycard_applets + wget https://github.com/martinpaljak/GlobalPlatformPro/releases/download/v25.10.20/gp.jar -P lez/keycard_wallet/keycard_applets + cd lez/keycard_wallet/keycard_applets java -jar gp.jar --key c212e073ff8b4bbfaff4de8ab655221f --load math.cap ``` 2. Install `keycard-desktop` from [github](https://github.com/choppu/keycard-desktop) - Keycard Desktop is used to install the LEE key protocol to a blank keycard. - - Select (Re)Install Applet and upload the key binary (`keycard_wallet/keycard_applets/LEE_keycard.cap`). + - Select (Re)Install Applet and upload the key binary (`lez/keycard_wallet/keycard_applets/LEE_keycard.cap`). ![keycard-desktop.png](keycard-desktop.png) - **Important:** keycard can only connect with one application at a time; if Keycard-Desktop is using keycard then Wallet CLI cannot access the same keycard, and vice-versa. ## Wallet with Keycard -Keycard functionality is available to Wallet CLI by setting up the following Python virtual environment. The steps below can also be run via `keycard_wallet/wallet_with_keycard.sh`. +Keycard functionality is available to Wallet CLI by setting up the following Python virtual environment. The steps below can also be run via `lez/keycard_wallet/wallet_with_keycard.sh`. ```bash # Install appropriate version of `keycard-py`. -git clone --branch lee-schnorr --single-branch https://github.com/bitgamma/keycard-py.git keycard_wallet/python/keycard-py +git clone --branch lee-schnorr --single-branch https://github.com/bitgamma/keycard-py.git lez/keycard_wallet/python/keycard-py # Set up virtual environment. python3 -m venv venv source venv/bin/activate pip install pyscard mnemonic ecdsa pyaes -pip install -e keycard_wallet/python/keycard-py +pip install -e lez/keycard_wallet/python/keycard-py ``` **Important**: Keycard wallet commands only work within the virtual environment. diff --git a/docs/LEZ testnet v0.1 tutorials/token-transfer.md b/docs/LEZ testnet v0.1 tutorials/token-transfer.md index 3a1ef43f..e3d04663 100644 --- a/docs/LEZ testnet v0.1 tutorials/token-transfer.md +++ b/docs/LEZ testnet v0.1 tutorials/token-transfer.md @@ -155,7 +155,7 @@ wallet account new private # Output: Generated new account with account_id Private/HacPU3hakLYzWtSqUPw6TUr8fqoMieVWovsUR6sJf7cL With npk e6366f79d026c8bd64ae6b3d601f0506832ec682ab54897f205fffe64ec0d951 -With vpk 02ddc96d0eb56e00ce14994cfdaec5ae1f76244180a919545983156e3519940a17 +With vpk <1184-byte ML-KEM-768 encapsulation key, hex-encoded> ``` > [!Tip] @@ -231,19 +231,29 @@ wallet account new private-accounts-key # Output: Generated new private accounts key at path /1 With npk 0c95ebc4b3830f53da77bb0b80a276a776cdcf6410932acc718dcdb3f788a00e -With vpk 039fd12a3674a880d3e917804129141e4170d419d1f9e28a3dcf979c1f2369cb72 +With vpk <1184-byte ML-KEM-768 encapsulation key, hex-encoded> ``` -> [!Tip] -> Ignore the account ID here and use the `npk` and `vpk` values to send to a foreign private account. +> [!Important] +> The VPK is now a 1184-byte ML-KEM-768 encapsulation key — too large to copy-paste into a command. +> The recommended workflow is: +> +> **Recipient:** export both keys to a single file and send the file to the sender (e.g. as an email attachment): +> ```bash +> wallet account show-keys --account-id Private/ > recipient.keys +> # Send recipient.keys to the sender out-of-band +> ``` +> The file contains two lines: the npk (hex) on line 1, the vpk (hex) on line 2. +> +> **Sender:** reference the received file with `--to-keys`: -### b. Send 3 tokens using the recipient’s npk and vpk +### b. Send 3 tokens using the recipient’s keys file ```bash +# The sender has received recipient.keys from the recipient out-of-band wallet auth-transfer send \ --from Public/Ev1JprP9BmhbFVQyBcbznU8bAXcwrzwRoPTetXdQPAWS \ - --to-npk 0c95ebc4b3830f53da77bb0b80a276a776cdcf6410932acc718dcdb3f788a00e \ - --to-vpk 039fd12a3674a880d3e917804129141e4170d419d1f9e28a3dcf979c1f2369cb72 \ + --to-keys recipient.keys \ --amount 3 ``` @@ -270,18 +280,19 @@ wallet account new private-accounts-key # Output: Generated new private accounts key at path /2 With npk a3f7c21b8e905d4f6a1bc783d0e2f94c1d5a6b7e8f9012345678abcdef012345 -With vpk 03b1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6071819202122232425262728292a2b2c +With vpk <1184-byte ML-KEM-768 encapsulation key, hex-encoded> ``` Alice shares the `npk` and `vpk` values with Bob and Charlie out of band. ### b. Bob sends 10 tokens to Alice using identifier 1 +Bob uses the received `alice.keys` file: + ```bash wallet auth-transfer send \ --from Public/BobXqJprP9BmhbFVQyBcbznU8bAXcwrzwRoPTetXdQPA \ - --to-npk a3f7c21b8e905d4f6a1bc783d0e2f94c1d5a6b7e8f9012345678abcdef012345 \ - --to-vpk 03b1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6071819202122232425262728292a2b2c \ + --to-keys alice.keys \ --to-identifier 1 \ --amount 10 ``` @@ -291,8 +302,7 @@ wallet auth-transfer send \ ```bash wallet auth-transfer send \ --from Public/CharlieYrP9BmhbFVQyBcbznU8bAXcwrzwRoPTetXdQPB \ - --to-npk a3f7c21b8e905d4f6a1bc783d0e2f94c1d5a6b7e8f9012345678abcdef012345 \ - --to-vpk 03b1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6071819202122232425262728292a2b2c \ + --to-keys alice.keys \ --to-identifier 2 \ --amount 5 ``` diff --git a/examples/program_deployment/Cargo.toml b/examples/program_deployment/Cargo.toml index c41d9247..c14bdbc5 100644 --- a/examples/program_deployment/Cargo.toml +++ b/examples/program_deployment/Cargo.toml @@ -9,8 +9,8 @@ workspace = true [dependencies] common.workspace = true -nssa.workspace = true -nssa_core.workspace = true +lee.workspace = true +lee_core.workspace = true sequencer_service_rpc = { workspace = true, features = ["client"] } wallet.workspace = true diff --git a/examples/program_deployment/README.md b/examples/program_deployment/README.md index 11952c35..6d1bde25 100644 --- a/examples/program_deployment/README.md +++ b/examples/program_deployment/README.md @@ -13,7 +13,7 @@ cargo install --path wallet --force ``` # 1. Run the sequencer -From the project’s root directory, start the sequencer by following [these instructions](https://github.com/logos-blockchain/lssa#run-the-sequencer-and-node). +From the project’s root directory, start the sequencer by following [these instructions](https://github.com/logos-blockchain/logos-execution-zone#run-the-sequencer-and-node). ## Checking and setting up the wallet For sanity let's check that the wallet can connect to it. @@ -28,7 +28,7 @@ For this tutorial, use: `program-tutorial` You should see `✅All looks good!` if everything went well. # 2. Compile the example programs -In a second terminal, from the `lssa` root directory, compile the example Risc0 programs: +In a second terminal, from the `logos-execution-zone` root directory, compile the example Risc0 programs: ```bash cargo risczero build --manifest-path examples/program_deployment/methods/guest/Cargo.toml ``` @@ -134,7 +134,7 @@ echo -n SG9sYSBtdW5kbyE= | base64 -d You should see `Hola mundo!`. # 5. Understanding the code in `hello_world.rs`. -The Hello world example demonstrates the minimal structure of an NSSA program. +The Hello world example demonstrates the minimal structure of a LEE program. Its purpose is very simple: append the instruction bytes to the data field of a single account. ### What this program does in a nutshell @@ -145,7 +145,7 @@ Its purpose is very simple: append the instruction bytes to the data field of a 2. Checks that there is exactly one input account: this example operates on a single account, so it expects `pre_states` to contain exactly one entry. 3. Builds the post-state: It clones the input account and appends the instruction bytes to its data field. 4. Handles account claiming logic: If the account is uninitialized (i.e. not yet claimed by any program), its program_owner will equal `DEFAULT_PROGRAM_ID`. In that case, the program issues a claim request, meaning: "This program now owns this account." -5. Outputs the proposed state transition: `write_nssa_outputs` emits: +5. Outputs the proposed state transition: `write_lee_outputs` emits: - The original instruction data - The original pre-states - The new post-states @@ -154,7 +154,7 @@ Its purpose is very simple: append the instruction bytes to the data field of a 1. Reading inputs: ```rust let (ProgramInput { pre_states, instruction: greeting }, instruction_data) - = read_nssa_inputs::(); + = read_lee_inputs::(); ``` 2. Extracting the single account: ```rust @@ -179,7 +179,7 @@ let post_state = if post_account.program_owner == DEFAULT_PROGRAM_ID { ``` 5. Emmiting the output ```rust -write_nssa_outputs(instruction_data, vec![pre_state], vec![post_state]); +write_lee_outputs(instruction_data, vec![pre_state], vec![post_state]); ``` # 6. Understanding the runner script `run_hello_world.rs` @@ -348,7 +348,7 @@ Check the `run_hello_world_private.rs` file to see how it is used. # 8. Account authorization mechanism The Hello world example does not enforce any authorization on the input account. This means any user can execute it on any account, regardless of ownership. -NSSA provides a mechanism for programs to enforce proper authorization before an execution can succeed. The meaning of authorization differs between public and private accounts: +LEE provides a mechanism for programs to enforce proper authorization before an execution can succeed. The meaning of authorization differs between public and private accounts: - Public accounts: authorization requires that the transaction is signed with the account’s signing key. - Private accounts: authorization requires that the circuit verifies knowledge of the account’s nullifier secret key. @@ -594,7 +594,7 @@ wallet account get --account-id Private/8vzkK7vsdrS2gdPhLk72La8X4FJkgJ5kJLUBRbEV ## Digression: account authority vs account program ownership -In NSSA there are two distinct concepts that control who can modify an account: +In LEE there are two distinct concepts that control who can modify an account: **Program Ownership:** Each account has a field: `program_owner: ProgramId`. This indicates which program is allowed to update the account’s state during execution. - If a program is the program_owner of an account, it can freely mutate its fields. diff --git a/examples/program_deployment/methods/guest/Cargo.toml b/examples/program_deployment/methods/guest/Cargo.toml index 69d0ffb1..e5771853 100644 --- a/examples/program_deployment/methods/guest/Cargo.toml +++ b/examples/program_deployment/methods/guest/Cargo.toml @@ -8,7 +8,7 @@ license = { workspace = true } workspace = true [dependencies] -nssa_core.workspace = true +lee_core.workspace = true hex.workspace = true bytemuck.workspace = true diff --git a/examples/program_deployment/methods/guest/src/bin/hello_world.rs b/examples/program_deployment/methods/guest/src/bin/hello_world.rs index 3e91db0e..0cb7f349 100644 --- a/examples/program_deployment/methods/guest/src/bin/hello_world.rs +++ b/examples/program_deployment/methods/guest/src/bin/hello_world.rs @@ -1,4 +1,4 @@ -use nssa_core::program::{AccountPostState, Claim, ProgramInput, ProgramOutput, read_nssa_inputs}; +use lee_core::program::{AccountPostState, Claim, ProgramInput, ProgramOutput, read_lee_inputs}; // Hello-world example program. // @@ -25,7 +25,7 @@ fn main() { instruction: greeting, }, instruction_data, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); // Unpack the input account pre state let [pre_state] = pre_states @@ -49,7 +49,7 @@ fn main() { // The output is a proposed state difference. It will only succeed if the pre states coincide // with the previous values of the accounts, and the transition to the post states conforms - // with the NSSA program rules. + // with the LEE program rules. // WARNING: constructing a `ProgramOutput` has no effect on its own. `.write()` must be // called to commit the output. ProgramOutput::new( diff --git a/examples/program_deployment/methods/guest/src/bin/hello_world_with_authorization.rs b/examples/program_deployment/methods/guest/src/bin/hello_world_with_authorization.rs index 70dfa2ae..a9b238ce 100644 --- a/examples/program_deployment/methods/guest/src/bin/hello_world_with_authorization.rs +++ b/examples/program_deployment/methods/guest/src/bin/hello_world_with_authorization.rs @@ -1,4 +1,4 @@ -use nssa_core::program::{AccountPostState, Claim, ProgramInput, ProgramOutput, read_nssa_inputs}; +use lee_core::program::{AccountPostState, Claim, ProgramInput, ProgramOutput, read_lee_inputs}; // Hello-world with authorization example program. // @@ -25,7 +25,7 @@ fn main() { instruction: greeting, }, instruction_data, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); // Unpack the input account pre state let [pre_state] = pre_states @@ -56,7 +56,7 @@ fn main() { // The output is a proposed state difference. It will only succeed if the pre states coincide // with the previous values of the accounts, and the transition to the post states conforms - // with the NSSA program rules. + // with the LEE program rules. // WARNING: constructing a `ProgramOutput` has no effect on its own. `.write()` must be // called to commit the output. ProgramOutput::new( diff --git a/examples/program_deployment/methods/guest/src/bin/hello_world_with_move_function.rs b/examples/program_deployment/methods/guest/src/bin/hello_world_with_move_function.rs index 4289349b..ebb146ec 100644 --- a/examples/program_deployment/methods/guest/src/bin/hello_world_with_move_function.rs +++ b/examples/program_deployment/methods/guest/src/bin/hello_world_with_move_function.rs @@ -1,6 +1,6 @@ -use nssa_core::{ +use lee_core::{ account::{AccountWithMetadata, Data}, - program::{AccountPostState, Claim, ProgramInput, ProgramOutput, read_nssa_inputs}, + program::{AccountPostState, Claim, ProgramInput, ProgramOutput, read_lee_inputs}, }; // Hello-world with write + move_data example program. @@ -72,7 +72,7 @@ fn main() { instruction: (function_id, data), }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let post_states = match (pre_states.as_slice(), function_id, data.len()) { ([account_pre], WRITE_FUNCTION_ID, _) => { diff --git a/examples/program_deployment/methods/guest/src/bin/simple_tail_call.rs b/examples/program_deployment/methods/guest/src/bin/simple_tail_call.rs index 716e5c29..8f7edcab 100644 --- a/examples/program_deployment/methods/guest/src/bin/simple_tail_call.rs +++ b/examples/program_deployment/methods/guest/src/bin/simple_tail_call.rs @@ -1,5 +1,5 @@ -use nssa_core::program::{ - AccountPostState, ChainedCall, ProgramId, ProgramInput, ProgramOutput, read_nssa_inputs, +use lee_core::program::{ + AccountPostState, ChainedCall, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, }; // Tail Call example program. @@ -33,7 +33,7 @@ fn main() { instruction: (), }, instruction_data, - ) = read_nssa_inputs::<()>(); + ) = read_lee_inputs::<()>(); // Unpack the input account pre state let [pre_state] = pre_states diff --git a/examples/program_deployment/methods/guest/src/bin/tail_call_with_pda.rs b/examples/program_deployment/methods/guest/src/bin/tail_call_with_pda.rs index 5ec9aaab..c4b2cd11 100644 --- a/examples/program_deployment/methods/guest/src/bin/tail_call_with_pda.rs +++ b/examples/program_deployment/methods/guest/src/bin/tail_call_with_pda.rs @@ -1,6 +1,5 @@ -use nssa_core::program::{ - AccountPostState, ChainedCall, PdaSeed, ProgramId, ProgramInput, ProgramOutput, - read_nssa_inputs, +use lee_core::program::{ + AccountPostState, ChainedCall, PdaSeed, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, }; // Tail Call with PDA example program. @@ -39,7 +38,7 @@ fn main() { instruction: (), }, instruction_data, - ) = read_nssa_inputs::<()>(); + ) = read_lee_inputs::<()>(); // Unpack the input account pre state let [pre_state] = pre_states diff --git a/examples/program_deployment/src/bin/run_hello_world.rs b/examples/program_deployment/src/bin/run_hello_world.rs index 3d89b1a4..ef5545f7 100644 --- a/examples/program_deployment/src/bin/run_hello_world.rs +++ b/examples/program_deployment/src/bin/run_hello_world.rs @@ -1,5 +1,5 @@ -use common::transaction::NSSATransaction; -use nssa::{ +use common::transaction::LeeTransaction; +use lee::{ AccountId, PublicTransaction, program::Program, public_transaction::{Message, WitnessSet}, @@ -11,7 +11,7 @@ use wallet::WalletCore; // // cargo risczero build --manifest-path examples/program_deployment/methods/guest/Cargo.toml // -// Note: you must run the above command from the root of the `lssa` repository. +// Note: you must run the above command from the root of the `logos-execution-zone` repository. // Note: The compiled binary file is stored in // methods/guest/target/riscv32im-risc0-zkvm-elf/docker/hello_world.bin // @@ -60,7 +60,7 @@ async fn main() { // Submit the transaction let _response = wallet_core .sequencer_client - .send_transaction(NSSATransaction::Public(tx)) + .send_transaction(LeeTransaction::Public(tx)) .await .unwrap(); } diff --git a/examples/program_deployment/src/bin/run_hello_world_private.rs b/examples/program_deployment/src/bin/run_hello_world_private.rs index 725019f1..088eb19a 100644 --- a/examples/program_deployment/src/bin/run_hello_world_private.rs +++ b/examples/program_deployment/src/bin/run_hello_world_private.rs @@ -1,11 +1,11 @@ -use nssa::{AccountId, program::Program}; +use lee::{AccountId, program::Program}; use wallet::{AccountIdentity, WalletCore}; // Before running this example, compile the `hello_world.rs` guest program with: // // cargo risczero build --manifest-path examples/program_deployment/methods/guest/Cargo.toml // -// Note: you must run the above command from the root of the `lssa` repository. +// Note: you must run the above command from the root of the `logos-execution-zone` repository. // Note: The compiled binary file is stored in // methods/guest/target/riscv32im-risc0-zkvm-elf/docker/hello_world.bin // diff --git a/examples/program_deployment/src/bin/run_hello_world_through_tail_call.rs b/examples/program_deployment/src/bin/run_hello_world_through_tail_call.rs index c3c75b5f..a5f449e1 100644 --- a/examples/program_deployment/src/bin/run_hello_world_through_tail_call.rs +++ b/examples/program_deployment/src/bin/run_hello_world_through_tail_call.rs @@ -1,5 +1,5 @@ -use common::transaction::NSSATransaction; -use nssa::{ +use common::transaction::LeeTransaction; +use lee::{ AccountId, PublicTransaction, program::Program, public_transaction::{Message, WitnessSet}, @@ -11,7 +11,7 @@ use wallet::WalletCore; // // cargo risczero build --manifest-path examples/program_deployment/methods/guest/Cargo.toml // -// Note: you must run the above command from the root of the `lssa` repository. +// Note: you must run the above command from the root of the `logos-execution-zone` repository. // Note: The compiled binary file is stored in // methods/guest/target/riscv32im-risc0-zkvm-elf/docker/simple_tail_call.bin // @@ -56,7 +56,7 @@ async fn main() { // Submit the transaction let _response = wallet_core .sequencer_client - .send_transaction(NSSATransaction::Public(tx)) + .send_transaction(LeeTransaction::Public(tx)) .await .unwrap(); } diff --git a/examples/program_deployment/src/bin/run_hello_world_through_tail_call_private.rs b/examples/program_deployment/src/bin/run_hello_world_through_tail_call_private.rs index d68e99dc..4983afdb 100644 --- a/examples/program_deployment/src/bin/run_hello_world_through_tail_call_private.rs +++ b/examples/program_deployment/src/bin/run_hello_world_through_tail_call_private.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use nssa::{ +use lee::{ AccountId, ProgramId, privacy_preserving_transaction::circuit::ProgramWithDependencies, program::Program, }; @@ -10,7 +10,7 @@ use wallet::{AccountIdentity, WalletCore}; // // cargo risczero build --manifest-path examples/program_deployment/methods/guest/Cargo.toml // -// Note: you must run the above command from the root of the `lssa` repository. +// Note: you must run the above command from the root of the `logos-execution-zone` repository. // Note: The compiled binary file is stored in // methods/guest/target/riscv32im-risc0-zkvm-elf/docker/simple_tail_call.bin // diff --git a/examples/program_deployment/src/bin/run_hello_world_with_authorization.rs b/examples/program_deployment/src/bin/run_hello_world_with_authorization.rs index 18b4ba80..15fc028a 100644 --- a/examples/program_deployment/src/bin/run_hello_world_with_authorization.rs +++ b/examples/program_deployment/src/bin/run_hello_world_with_authorization.rs @@ -1,5 +1,5 @@ -use common::transaction::NSSATransaction; -use nssa::{ +use common::transaction::LeeTransaction; +use lee::{ AccountId, PublicTransaction, program::Program, public_transaction::{Message, WitnessSet}, @@ -11,7 +11,7 @@ use wallet::WalletCore; // // cargo risczero build --manifest-path examples/program_deployment/methods/guest/Cargo.toml // -// Note: you must run the above command from the root of the `lssa` repository. +// Note: you must run the above command from the root of the `logos-execution-zone` repository. // Note: The compiled binary file is stored in // methods/guest/target/riscv32im-risc0-zkvm-elf/docker/hello_world_with_authorization.bin // @@ -73,7 +73,7 @@ async fn main() { // Submit the transaction let _response = wallet_core .sequencer_client - .send_transaction(NSSATransaction::Public(tx)) + .send_transaction(LeeTransaction::Public(tx)) .await .unwrap(); } diff --git a/examples/program_deployment/src/bin/run_hello_world_with_authorization_through_tail_call_with_pda.rs b/examples/program_deployment/src/bin/run_hello_world_with_authorization_through_tail_call_with_pda.rs index 86c95ebf..2b0e05ed 100644 --- a/examples/program_deployment/src/bin/run_hello_world_with_authorization_through_tail_call_with_pda.rs +++ b/examples/program_deployment/src/bin/run_hello_world_with_authorization_through_tail_call_with_pda.rs @@ -3,13 +3,13 @@ reason = "This is an example program, it's fine to print to stdout" )] -use common::transaction::NSSATransaction; -use nssa::{ +use common::transaction::LeeTransaction; +use lee::{ AccountId, PublicTransaction, program::Program, public_transaction::{Message, WitnessSet}, }; -use nssa_core::program::PdaSeed; +use lee_core::program::PdaSeed; use sequencer_service_rpc::RpcClient as _; use wallet::WalletCore; @@ -17,7 +17,7 @@ use wallet::WalletCore; // // cargo risczero build --manifest-path examples/program_deployment/methods/guest/Cargo.toml // -// Note: you must run the above command from the root of the `lssa` repository. +// Note: you must run the above command from the root of the `logos-execution-zone` repository. // Note: The compiled binary file is stored in // methods/guest/target/riscv32im-risc0-zkvm-elf/docker/simple_tail_call.bin // @@ -58,7 +58,7 @@ async fn main() { // Submit the transaction let _response = wallet_core .sequencer_client - .send_transaction(NSSATransaction::Public(tx)) + .send_transaction(LeeTransaction::Public(tx)) .await .unwrap(); diff --git a/examples/program_deployment/src/bin/run_hello_world_with_move_function.rs b/examples/program_deployment/src/bin/run_hello_world_with_move_function.rs index e6f667a6..3b175bda 100644 --- a/examples/program_deployment/src/bin/run_hello_world_with_move_function.rs +++ b/examples/program_deployment/src/bin/run_hello_world_with_move_function.rs @@ -1,6 +1,6 @@ use clap::{Parser, Subcommand}; -use common::transaction::NSSATransaction; -use nssa::{PublicTransaction, program::Program, public_transaction}; +use common::transaction::LeeTransaction; +use lee::{PublicTransaction, program::Program, public_transaction}; use sequencer_service_rpc::RpcClient as _; use wallet::{AccountIdentity, WalletCore}; @@ -8,7 +8,7 @@ use wallet::{AccountIdentity, WalletCore}; // // cargo risczero build --manifest-path examples/program_deployment/methods/guest/Cargo.toml // -// Note: you must run the above command from the root of the `lssa` repository. +// Note: you must run the above command from the root of the `logos-execution-zone` repository. // Note: The compiled binary file is stored in // methods/guest/target/riscv32im-risc0-zkvm-elf/docker/hello_world_with_move_function.bin // @@ -89,7 +89,7 @@ async fn main() { // Submit the transaction let _response = wallet_core .sequencer_client - .send_transaction(NSSATransaction::Public(tx)) + .send_transaction(LeeTransaction::Public(tx)) .await .unwrap(); } @@ -128,7 +128,7 @@ async fn main() { // Submit the transaction let _response = wallet_core .sequencer_client - .send_transaction(NSSATransaction::Public(tx)) + .send_transaction(LeeTransaction::Public(tx)) .await .unwrap(); } diff --git a/integration_tests/Cargo.toml b/integration_tests/Cargo.toml index 82d8ebd1..b35f9deb 100644 --- a/integration_tests/Cargo.toml +++ b/integration_tests/Cargo.toml @@ -10,8 +10,8 @@ workspace = true [dependencies] test_fixtures.workspace = true -nssa_core = { workspace = true, features = ["host"] } -nssa.workspace = true +lee_core = { workspace = true, features = ["host"] } +lee.workspace = true authenticated_transfer_core.workspace = true sequencer_core = { workspace = true, features = ["default", "testnet"] } wallet.workspace = true @@ -22,6 +22,7 @@ token_core.workspace = true ata_core.workspace = true vault_core.workspace = true faucet_core.workspace = true +bridge_core.workspace = true indexer_service_rpc = { workspace = true, features = ["client"] } sequencer_service_rpc = { workspace = true, features = ["client"] } wallet-ffi.workspace = true @@ -34,3 +35,7 @@ tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } hex.workspace = true tempfile.workspace = true bytesize.workspace = true +reqwest.workspace = true +borsh.workspace = true +logos-blockchain-http-api-common.workspace = true +logos-blockchain-core.workspace = true diff --git a/integration_tests/src/lib.rs b/integration_tests/src/lib.rs index d3fa7c64..48f69559 100644 --- a/integration_tests/src/lib.rs +++ b/integration_tests/src/lib.rs @@ -3,4 +3,49 @@ //! non-test consumers (e.g. `integration_bench`) can depend on them without //! pulling in the test files. +use std::time::Duration; + +use anyhow::{Context as _, Result}; +use log::info; pub use test_fixtures::*; + +/// Maximum time to wait for the indexer to catch up to the sequencer. +pub const L2_TO_L1_TIMEOUT: Duration = Duration::from_mins(6); + +/// Poll the indexer until its last finalized block id reaches the sequencer's +/// current last block id or until [`L2_TO_L1_TIMEOUT`] elapses. +/// Returns the last indexer block id observed. +pub async fn wait_for_indexer_to_catch_up(ctx: &TestContext) -> Result { + use indexer_service_rpc::RpcClient as _; + + let block_id_to_catch_up = + sequencer_service_rpc::RpcClient::get_last_block_id(ctx.sequencer_client()).await?; + let mut last_ind: u64 = 1; + let inner = async { + loop { + let ind = ctx + .indexer_client() + .get_last_finalized_block_id() + .await? + .unwrap_or(0); + last_ind = ind; + if ind >= block_id_to_catch_up { + let last_seq = + sequencer_service_rpc::RpcClient::get_last_block_id(ctx.sequencer_client()) + .await?; + info!( + "Indexer caught up. Indexer last block id: {ind}. Current sequencer last block id: {last_seq}" + ); + return Ok(ind); + } + tokio::time::sleep(Duration::from_secs(2)).await; + } + }; + tokio::time::timeout(L2_TO_L1_TIMEOUT, inner) + .await + .with_context(|| { + format!( + "Indexer failed to catch up within {L2_TO_L1_TIMEOUT:?}. Last indexer block id observed: {last_ind}, but needed to catch up to at least {block_id_to_catch_up}" + ) + })? +} diff --git a/integration_tests/tests/account.rs b/integration_tests/tests/account.rs index f779695d..3d5854cf 100644 --- a/integration_tests/tests/account.rs +++ b/integration_tests/tests/account.rs @@ -6,9 +6,9 @@ use anyhow::{Context as _, Result}; use integration_tests::{TestContext, private_mention}; use key_protocol::key_management::KeyChain; +use lee::{Data, program::Program}; +use lee_core::account::Nonce; use log::info; -use nssa::{Data, program::Program}; -use nssa_core::account::Nonce; use sequencer_service_rpc::RpcClient as _; use tokio::test; use wallet::{ @@ -127,8 +127,8 @@ async fn new_public_account_without_label() -> Result<()> { async fn import_public_account() -> Result<()> { let mut ctx = TestContext::new().await?; - let private_key = nssa::PrivateKey::new_os_random(); - let account_id = nssa::AccountId::from(&nssa::PublicKey::new_from_private_key(&private_key)); + let private_key = lee::PrivateKey::new_os_random(); + let account_id = lee::AccountId::from(&lee::PublicKey::new_from_private_key(&private_key)); let command = Command::Account(AccountSubcommand::Import(ImportSubcommand::Public { private_key, @@ -156,8 +156,8 @@ async fn import_private_account() -> Result<()> { let mut ctx = TestContext::new().await?; let key_chain = KeyChain::new_os_random(); - let account_id = nssa::AccountId::from((&key_chain.nullifier_public_key, 0)); - let account = nssa::Account { + let account_id = lee::AccountId::from((&key_chain.nullifier_public_key, 0)); + let account = lee::Account { program_owner: Program::authenticated_transfer_program().id(), balance: 777, data: Data::default(), @@ -213,11 +213,11 @@ async fn import_private_account_second_time_overrides_account_data() -> Result<( let mut ctx = TestContext::new().await?; let key_chain = KeyChain::new_os_random(); - let account_id = nssa::AccountId::from((&key_chain.nullifier_public_key, 0)); + let account_id = lee::AccountId::from((&key_chain.nullifier_public_key, 0)); let key_chain_json = serde_json::to_string(&key_chain).context("Failed to serialize key chain")?; - let initial_account = nssa::Account { + let initial_account = lee::Account { program_owner: Program::authenticated_transfer_program().id(), balance: 100, data: Data::default(), @@ -236,7 +236,7 @@ async fn import_private_account_second_time_overrides_account_data() -> Result<( ) .await?; - let updated_account = nssa::Account { + let updated_account = lee::Account { program_owner: Program::authenticated_transfer_program().id(), balance: 999, data: Data::default(), diff --git a/integration_tests/tests/amm.rs b/integration_tests/tests/amm.rs index b7a747f1..9f953001 100644 --- a/integration_tests/tests/amm.rs +++ b/integration_tests/tests/amm.rs @@ -132,6 +132,7 @@ async fn amm_public() -> Result<()> { to: Some(public_mention(recipient_account_id_1)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: 7, }; @@ -158,6 +159,7 @@ async fn amm_public() -> Result<()> { to: Some(public_mention(recipient_account_id_2)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: 7, }; @@ -530,6 +532,7 @@ async fn amm_new_pool_using_labels() -> Result<()> { to: Some(public_mention(holding_a_id)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: 5, }; @@ -551,6 +554,7 @@ async fn amm_new_pool_using_labels() -> Result<()> { to: Some(public_mention(holding_b_id)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: 5, }; diff --git a/integration_tests/tests/ata.rs b/integration_tests/tests/ata.rs index d0eddeae..9e37061b 100644 --- a/integration_tests/tests/ata.rs +++ b/integration_tests/tests/ata.rs @@ -12,8 +12,8 @@ use integration_tests::{ TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, private_mention, public_mention, verify_commitment_is_in_state, }; +use lee::program::Program; use log::info; -use nssa::program::Program; use sequencer_service_rpc::RpcClient as _; use token_core::{TokenDefinition, TokenHolding}; use tokio::test; @@ -24,7 +24,7 @@ use wallet::cli::{ }; /// Create a public account and return its ID. -async fn new_public_account(ctx: &mut TestContext) -> Result { +async fn new_public_account(ctx: &mut TestContext) -> Result { let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), Command::Account(AccountSubcommand::New(NewSubcommand::Public { @@ -40,7 +40,7 @@ async fn new_public_account(ctx: &mut TestContext) -> Result { } /// Create a private account and return its ID. -async fn new_private_account(ctx: &mut TestContext) -> Result { +async fn new_private_account(ctx: &mut TestContext) -> Result { let result = wallet::cli::execute_subcommand( ctx.wallet_mut(), Command::Account(AccountSubcommand::New(NewSubcommand::Private { @@ -260,6 +260,7 @@ async fn transfer_and_burn_via_ata() -> Result<()> { to: Some(public_mention(sender_ata_id)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: fund_amount, }), @@ -487,6 +488,7 @@ async fn transfer_via_ata_private_owner() -> Result<()> { to: Some(public_mention(sender_ata_id)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: fund_amount, }), @@ -598,6 +600,7 @@ async fn burn_via_ata_private_owner() -> Result<()> { to: Some(public_mention(holder_ata_id)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: fund_amount, }), diff --git a/integration_tests/tests/auth_transfer/private.rs b/integration_tests/tests/auth_transfer/private.rs index a77ccf34..9eea9b04 100644 --- a/integration_tests/tests/auth_transfer/private.rs +++ b/integration_tests/tests/auth_transfer/private.rs @@ -1,14 +1,21 @@ use std::time::Duration; use anyhow::{Context as _, Result}; -use common::transaction::NSSATransaction; +use common::transaction::LeeTransaction; use integration_tests::{ TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, fetch_privacy_preserving_tx, private_mention, public_mention, verify_commitment_is_in_state, }; +use lee::{ + AccountId, SharedSecretKey, execute_and_prove, + privacy_preserving_transaction::circuit::ProgramWithDependencies, program::Program, +}; +use lee_core::{ + InputAccountIdentity, NullifierPublicKey, + account::AccountWithMetadata, + encryption::{EphemeralPublicKey, ViewingPublicKey}, +}; use log::info; -use nssa::{AccountId, program::Program}; -use nssa_core::{NullifierPublicKey, encryption::shared_key_derivation::Secp256k1Point}; use sequencer_service_rpc::RpcClient as _; use tokio::test; use wallet::{ @@ -32,6 +39,7 @@ async fn private_transfer_to_owned_account() -> Result<()> { to: Some(private_mention(to)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: 100, }); @@ -65,13 +73,14 @@ async fn private_transfer_to_foreign_account() -> Result<()> { let from: AccountId = ctx.existing_private_accounts()[0]; let to_npk = NullifierPublicKey([42; 32]); let to_npk_string = hex::encode(to_npk.0); - let to_vpk = Secp256k1Point::from_scalar(to_npk.0); + let to_vpk = ViewingPublicKey::from_seed(&[0_u8; 32], &[1_u8; 32]); let command = Command::AuthTransfer(AuthTransferSubcommand::Send { from: private_mention(from), to: None, to_npk: Some(to_npk_string), - to_vpk: Some(hex::encode(to_vpk.0)), + to_vpk: Some(hex::encode(to_vpk.to_bytes())), + to_keys: None, to_identifier: Some(0), amount: 100, }); @@ -121,6 +130,7 @@ async fn deshielded_transfer_to_public_account() -> Result<()> { to: Some(public_mention(to)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: 100, }); @@ -183,7 +193,8 @@ async fn private_transfer_to_owned_account_using_claiming_path() -> Result<()> { from: private_mention(from), to: None, to_npk: Some(hex::encode(to.key_chain.nullifier_public_key.0)), - to_vpk: Some(hex::encode(&to.key_chain.viewing_public_key.0)), + to_vpk: Some(hex::encode(to.key_chain.viewing_public_key.to_bytes())), + to_keys: None, to_identifier: Some(to.kind.identifier()), amount: 100, }); @@ -233,6 +244,7 @@ async fn shielded_transfer_to_owned_private_account() -> Result<()> { to: Some(private_mention(to)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: 100, }); @@ -268,14 +280,15 @@ async fn shielded_transfer_to_foreign_account() -> Result<()> { let to_npk = NullifierPublicKey([42; 32]); let to_npk_string = hex::encode(to_npk.0); - let to_vpk = Secp256k1Point::from_scalar(to_npk.0); + let to_vpk = ViewingPublicKey::from_seed(&[0_u8; 32], &[1_u8; 32]); let from: AccountId = ctx.existing_public_accounts()[0]; let command = Command::AuthTransfer(AuthTransferSubcommand::Send { from: public_mention(from), to: None, to_npk: Some(to_npk_string), - to_vpk: Some(hex::encode(to_vpk.0)), + to_vpk: Some(hex::encode(to_vpk.to_bytes())), + to_keys: None, to_identifier: Some(0), amount: 100, }); @@ -345,7 +358,8 @@ async fn private_transfer_to_owned_account_continuous_run_path() -> Result<()> { from: private_mention(from), to: None, to_npk: Some(hex::encode(to.key_chain.nullifier_public_key.0)), - to_vpk: Some(hex::encode(&to.key_chain.viewing_public_key.0)), + to_vpk: Some(hex::encode(to.key_chain.viewing_public_key.to_bytes())), + to_keys: None, to_identifier: Some(to.kind.identifier()), amount: 100, }); @@ -446,6 +460,7 @@ async fn private_transfer_using_from_label() -> Result<()> { to: Some(private_mention(to)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: 100, }); @@ -539,7 +554,7 @@ async fn shielded_transfers_to_two_identifiers_same_npk() -> Result<()> { }; let npk_hex = hex::encode(npk.0); - let vpk_hex = hex::encode(vpk.0); + let vpk_hex = hex::encode(vpk.to_bytes()); let identifier_1 = 1_u128; let identifier_2 = 2_u128; @@ -554,6 +569,7 @@ async fn shielded_transfers_to_two_identifiers_same_npk() -> Result<()> { to: None, to_npk: Some(npk_hex.clone()), to_vpk: Some(vpk_hex.clone()), + to_keys: None, to_identifier: Some(identifier_1), amount: 100, }), @@ -567,6 +583,7 @@ async fn shielded_transfers_to_two_identifiers_same_npk() -> Result<()> { to: None, to_npk: Some(npk_hex), to_vpk: Some(vpk_hex), + to_keys: None, to_identifier: Some(identifier_2), amount: 200, }), @@ -626,37 +643,31 @@ async fn shielded_transfers_to_two_identifiers_same_npk() -> Result<()> { } #[test] -async fn ppt_that_chain_calls_faucet_is_dropped() -> Result<()> { - use nssa::{ - EphemeralPublicKey, SharedSecretKey, execute_and_prove, - privacy_preserving_transaction::{self, circuit::ProgramWithDependencies}, - }; - use nssa_core::{InputAccountIdentity, account::AccountWithMetadata}; - +async fn ppt_cant_chain_call_faucet() -> Result<()> { let ctx = TestContext::new().await?; let binary = std::fs::read( std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")) .join("../artifacts/test_program_methods/faucet_chain_caller.bin"), )?; - let deploy_tx = NSSATransaction::ProgramDeployment(nssa::ProgramDeploymentTransaction::new( - nssa::program_deployment_transaction::Message::new(binary.clone()), + let deploy_tx = LeeTransaction::ProgramDeployment(lee::ProgramDeploymentTransaction::new( + lee::program_deployment_transaction::Message::new(binary.clone()), )); ctx.sequencer_client().send_transaction(deploy_tx).await?; info!("Waiting for deploy block creation"); tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - let faucet_account_id = nssa::system_faucet_account_id(); + let faucet_account_id = lee::system_faucet_account_id(); let attacker_id = ctx.existing_public_accounts()[0]; let faucet_program_id = Program::faucet().id(); let vault_program_id = Program::vault().id(); let auth_transfer_program_id = Program::authenticated_transfer_program().id(); - let nsk: nssa_core::NullifierSecretKey = [3; 32]; + let nsk: lee_core::NullifierSecretKey = [3; 32]; let npk = NullifierPublicKey::from(&nsk); - let vpk = Secp256k1Point::from_scalar([4; 32]); - let ssk = SharedSecretKey::new([55; 32], &vpk); - let epk = EphemeralPublicKey::from_scalar([55; 32]); + let _vpk = ViewingPublicKey::from_bytes(vec![4_u8; 1184]).unwrap(); + let ssk = SharedSecretKey([55_u8; 32]); + let _epk = EphemeralPublicKey(vec![55_u8; 1088]); let attacker_vault_id = { let seed = vault_core::compute_vault_seed(attacker_id); AccountId::for_private_pda(&vault_program_id, &seed, &npk, 1337) @@ -695,7 +706,7 @@ async fn ppt_that_chain_calls_faucet_is_dropped() -> Result<()> { let instruction = Program::serialize_instruction((faucet_program_id, vault_program_id, attacker_id, amount))?; - let (output, proof) = execute_and_prove( + let res = execute_and_prove( vec![faucet_pre, vault_pda_pre], instruction, vec![ @@ -708,47 +719,9 @@ async fn ppt_that_chain_calls_faucet_is_dropped() -> Result<()> { }, ], &program_with_deps, - )?; + ); - let message = privacy_preserving_transaction::Message::try_from_circuit_output( - vec![faucet_account_id], - vec![], - vec![(npk, vpk, epk)], - output, - )?; - let witness_set = privacy_preserving_transaction::WitnessSet::for_message(&message, proof, &[]); - let attack_ppt = NSSATransaction::PrivacyPreserving(nssa::PrivacyPreservingTransaction::new( - message, - witness_set, - )); - - let faucet_balance_before = ctx - .sequencer_client() - .get_account_balance(faucet_account_id) - .await?; - let vault_balance_before = ctx - .sequencer_client() - .get_account_balance(attacker_vault_id) - .await?; - - let tx_hash = ctx.sequencer_client().send_transaction(attack_ppt).await?; - - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - let faucet_balance_after = ctx - .sequencer_client() - .get_account_balance(faucet_account_id) - .await?; - let vault_balance_after = ctx - .sequencer_client() - .get_account_balance(attacker_vault_id) - .await?; - let tx_on_chain = ctx.sequencer_client().get_transaction(tx_hash).await?; - - assert_eq!(faucet_balance_after, faucet_balance_before); - assert_eq!(vault_balance_after, vault_balance_before); - assert!(tx_on_chain.is_none()); + assert!(res.is_err()); Ok(()) } diff --git a/integration_tests/tests/auth_transfer/public.rs b/integration_tests/tests/auth_transfer/public.rs index 72685d0b..d00b7964 100644 --- a/integration_tests/tests/auth_transfer/public.rs +++ b/integration_tests/tests/auth_transfer/public.rs @@ -1,10 +1,10 @@ use std::{path::PathBuf, time::Duration}; use anyhow::Result; -use common::transaction::NSSATransaction; +use common::transaction::LeeTransaction; use integration_tests::{TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, public_mention}; +use lee::{program::Program, public_transaction, system_faucet_account_id}; use log::info; -use nssa::{program::Program, public_transaction, system_faucet_account_id}; use sequencer_service_rpc::RpcClient as _; use tokio::test; use wallet::{ @@ -25,6 +25,7 @@ async fn successful_transfer_to_existing_account() -> Result<()> { to: Some(public_mention(ctx.existing_public_accounts()[1])), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: 100, }); @@ -83,6 +84,7 @@ pub async fn successful_transfer_to_new_account() -> Result<()> { to: Some(public_mention(new_persistent_account_id)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: 100, }); @@ -120,6 +122,7 @@ async fn failed_transfer_with_insufficient_balance() -> Result<()> { to: Some(public_mention(ctx.existing_public_accounts()[1])), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: 1_000_000, }); @@ -159,6 +162,7 @@ async fn two_consecutive_successful_transfers() -> Result<()> { to: Some(public_mention(ctx.existing_public_accounts()[1])), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: 100, }); @@ -192,6 +196,7 @@ async fn two_consecutive_successful_transfers() -> Result<()> { to: Some(public_mention(ctx.existing_public_accounts()[1])), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: 100, }); @@ -274,6 +279,7 @@ async fn successful_transfer_using_from_label() -> Result<()> { to: Some(public_mention(ctx.existing_public_accounts()[1])), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: 100, }); @@ -319,6 +325,7 @@ async fn successful_transfer_using_to_label() -> Result<()> { to: Some(CliAccountMention::Label(label)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: 100, }); @@ -368,13 +375,13 @@ async fn cannot_transfer_funds_from_system_faucet_account() -> Result<()> { vec![], authenticated_transfer_core::Instruction::Transfer { amount }, )?; - let tx = nssa::PublicTransaction::new( + let tx = lee::PublicTransaction::new( message, - nssa::public_transaction::WitnessSet::from_raw_parts(vec![]), + lee::public_transaction::WitnessSet::from_raw_parts(vec![]), ); let tx_hash = ctx .sequencer_client() - .send_transaction(NSSATransaction::Public(tx)) + .send_transaction(LeeTransaction::Public(tx)) .await?; info!("Waiting for next block creation"); @@ -420,19 +427,19 @@ async fn cannot_execute_faucet_program() -> Result<()> { Program::faucet().id(), vec![faucet_account_id, recipient_vault_id], vec![], - faucet_core::Instruction::Transfer { + faucet_core::Instruction::GenesisTransferVault { vault_program_id, recipient_id: recipient, amount, }, )?; - let tx = nssa::PublicTransaction::new( + let tx = lee::PublicTransaction::new( message, - nssa::public_transaction::WitnessSet::from_raw_parts(vec![]), + lee::public_transaction::WitnessSet::from_raw_parts(vec![]), ); let tx_hash = ctx .sequencer_client() - .send_transaction(NSSATransaction::Public(tx)) + .send_transaction(LeeTransaction::Public(tx)) .await?; info!("Waiting for next block creation"); @@ -464,8 +471,8 @@ async fn user_tx_that_chain_calls_faucet_is_dropped() -> Result<()> { .join("../artifacts/test_program_methods/faucet_chain_caller.bin"), )?; let faucet_chain_caller_id = Program::new(binary.clone())?.id(); - let deploy_tx = NSSATransaction::ProgramDeployment(nssa::ProgramDeploymentTransaction::new( - nssa::program_deployment_transaction::Message::new(binary), + let deploy_tx = LeeTransaction::ProgramDeployment(lee::ProgramDeploymentTransaction::new( + lee::program_deployment_transaction::Message::new(binary), )); ctx.sequencer_client().send_transaction(deploy_tx).await?; @@ -485,9 +492,9 @@ async fn user_tx_that_chain_calls_faucet_is_dropped() -> Result<()> { vec![], (faucet_program_id, vault_program_id, attacker, amount), )?; - let attack_tx = NSSATransaction::Public(nssa::PublicTransaction::new( + let attack_tx = LeeTransaction::Public(lee::PublicTransaction::new( message, - nssa::public_transaction::WitnessSet::from_raw_parts(vec![]), + lee::public_transaction::WitnessSet::from_raw_parts(vec![]), )); let faucet_balance_before = ctx diff --git a/integration_tests/tests/block_size_limit.rs b/integration_tests/tests/block_size_limit.rs index 72f773c9..d95150f5 100644 --- a/integration_tests/tests/block_size_limit.rs +++ b/integration_tests/tests/block_size_limit.rs @@ -8,11 +8,11 @@ use std::time::Duration; use anyhow::Result; use bytesize::ByteSize; -use common::transaction::NSSATransaction; +use common::transaction::LeeTransaction; use integration_tests::{ TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, config::SequencerPartialConfig, }; -use nssa::program::Program; +use lee::program::Program; use sequencer_service_rpc::RpcClient as _; use tokio::test; @@ -33,13 +33,13 @@ async fn reject_oversized_transaction() -> Result<()> { // Create a 1.1 MiB binary to ensure it exceeds the limit let oversized_binary = vec![0_u8; 1100 * 1024]; // 1.1 MiB binary - let message = nssa::program_deployment_transaction::Message::new(oversized_binary); - let tx = nssa::ProgramDeploymentTransaction::new(message); + let message = lee::program_deployment_transaction::Message::new(oversized_binary); + let tx = lee::ProgramDeploymentTransaction::new(message); // Try to submit the transaction and expect an error let result = ctx .sequencer_client() - .send_transaction(NSSATransaction::ProgramDeployment(tx)) + .send_transaction(LeeTransaction::ProgramDeployment(tx)) .await; assert!( @@ -74,13 +74,13 @@ async fn accept_transaction_within_limit() -> Result<()> { // Create a small program deployment that should fit let small_binary = vec![0_u8; 1024]; // 1 KiB binary - let message = nssa::program_deployment_transaction::Message::new(small_binary); - let tx = nssa::ProgramDeploymentTransaction::new(message); + let message = lee::program_deployment_transaction::Message::new(small_binary); + let tx = lee::ProgramDeploymentTransaction::new(message); // This should succeed let result = ctx .sequencer_client() - .send_transaction(NSSATransaction::ProgramDeployment(tx)) + .send_transaction(LeeTransaction::ProgramDeployment(tx)) .await; assert!( @@ -123,17 +123,17 @@ async fn transaction_deferred_to_next_block_when_current_full() -> Result<()> { // Submit both program deployments ctx.sequencer_client() - .send_transaction(NSSATransaction::ProgramDeployment( - nssa::ProgramDeploymentTransaction::new( - nssa::program_deployment_transaction::Message::new(burner_bytecode), + .send_transaction(LeeTransaction::ProgramDeployment( + lee::ProgramDeploymentTransaction::new( + lee::program_deployment_transaction::Message::new(burner_bytecode), ), )) .await?; ctx.sequencer_client() - .send_transaction(NSSATransaction::ProgramDeployment( - nssa::ProgramDeploymentTransaction::new( - nssa::program_deployment_transaction::Message::new(chain_caller_bytecode), + .send_transaction(LeeTransaction::ProgramDeployment( + lee::ProgramDeploymentTransaction::new( + lee::program_deployment_transaction::Message::new(chain_caller_bytecode), ), )) .await?; @@ -148,13 +148,13 @@ async fn transaction_deferred_to_next_block_when_current_full() -> Result<()> { .unwrap(); // Check which program is in block 1 - let get_program_ids = |block: &common::block::Block| -> Vec { + let get_program_ids = |block: &common::block::Block| -> Vec { block .body .transactions .iter() .filter_map(|tx| { - if let NSSATransaction::ProgramDeployment(deployment) = tx { + if let LeeTransaction::ProgramDeployment(deployment) = tx { let bytecode = deployment.message.clone().into_bytecode(); Program::new(bytecode).ok().map(|p| p.id()) } else { diff --git a/integration_tests/tests/bridge.rs b/integration_tests/tests/bridge.rs new file mode 100644 index 00000000..81f62f2b --- /dev/null +++ b/integration_tests/tests/bridge.rs @@ -0,0 +1,454 @@ +#![expect( + clippy::tests_outside_test_module, + clippy::arithmetic_side_effects, + reason = "We don't care about these in tests" +)] + +use std::time::Duration; + +use anyhow::Context as _; +use borsh::BorshSerialize; +use common::transaction::LeeTransaction; +use integration_tests::{TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext}; +use lee::{ + AccountId, execute_and_prove, privacy_preserving_transaction, program::Program, + public_transaction, +}; +use lee_core::{InputAccountIdentity, account::AccountWithMetadata}; +use log::info; +use logos_blockchain_core::mantle::{Value, ledger::Inputs, ops::channel::deposit::DepositOp}; +use logos_blockchain_http_api_common::bodies::{ + channel::ChannelDepositRequestBody, + wallet::{ + balance::WalletBalanceResponseBody, + transfer_funds::{WalletTransferFundsRequestBody, WalletTransferFundsResponseBody}, + }, +}; +use sequencer_service_rpc::RpcClient as _; +use tokio::test; + +const TIME_TO_FINALIZE_DEPOSIT_EVENT_ON_BEDROCK: Duration = Duration::from_mins(2); + +#[test] +async fn public_bridge_deposit_invocation_is_dropped() -> anyhow::Result<()> { + let ctx = TestContext::new().await?; + + let recipient_id = ctx.existing_public_accounts()[0]; + let bridge_account_id = lee::system_bridge_account_id(); + let vault_program_id = Program::vault().id(); + let recipient_vault_id = vault_core::compute_vault_account_id(vault_program_id, recipient_id); + + let message = public_transaction::Message::try_new( + Program::bridge().id(), + vec![bridge_account_id, recipient_vault_id], + vec![], + bridge_core::Instruction::Deposit { + l1_deposit_op_id: [0_u8; 32], + vault_program_id, + recipient_id, + amount: 1, + }, + ) + .context("Failed to build public bridge deposit transaction")?; + + let attack_tx = LeeTransaction::Public(lee::PublicTransaction::new( + message, + lee::public_transaction::WitnessSet::from_raw_parts(vec![]), + )); + + let bridge_balance_before = ctx + .sequencer_client() + .get_account_balance(bridge_account_id) + .await?; + let vault_balance_before = ctx + .sequencer_client() + .get_account_balance(recipient_vault_id) + .await?; + + let tx_hash = ctx.sequencer_client().send_transaction(attack_tx).await?; + + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let bridge_balance_after = ctx + .sequencer_client() + .get_account_balance(bridge_account_id) + .await?; + let vault_balance_after = ctx + .sequencer_client() + .get_account_balance(recipient_vault_id) + .await?; + let tx_on_chain = ctx.sequencer_client().get_transaction(tx_hash).await?; + + assert_eq!(bridge_balance_after, bridge_balance_before); + assert_eq!(vault_balance_after, vault_balance_before); + assert!( + tx_on_chain.is_none(), + "Direct public bridge::Deposit invocation should be rejected" + ); + + Ok(()) +} + +#[test] +async fn private_bridge_deposit_invocation_is_dropped() -> anyhow::Result<()> { + let ctx = TestContext::new().await?; + + let recipient_id = ctx.existing_public_accounts()[0]; + let bridge_account_id = lee::system_bridge_account_id(); + let vault_program_id = Program::vault().id(); + let recipient_vault_id = vault_core::compute_vault_account_id(vault_program_id, recipient_id); + + // Get pre-state of bridge and vault accounts + let bridge_pre = AccountWithMetadata::new( + ctx.sequencer_client() + .get_account(bridge_account_id) + .await?, + false, + bridge_account_id, + ); + let vault_pre = AccountWithMetadata::new( + ctx.sequencer_client() + .get_account(recipient_vault_id) + .await?, + false, + recipient_vault_id, + ); + + // Create program with dependencies + let program_with_deps = + lee::privacy_preserving_transaction::circuit::ProgramWithDependencies::new( + Program::bridge(), + [ + (vault_program_id, Program::vault()), + ( + Program::authenticated_transfer_program().id(), + Program::authenticated_transfer_program(), + ), + ] + .into(), + ); + + // Serialize the bridge deposit instruction + let instruction = Program::serialize_instruction(bridge_core::Instruction::Deposit { + l1_deposit_op_id: [0_u8; 32], + vault_program_id, + recipient_id, + amount: 1, + }) + .context("Failed to serialize bridge deposit instruction")?; + + // Execute and prove the bridge deposit + let (output, proof) = execute_and_prove( + vec![bridge_pre.clone(), vault_pre.clone()], + instruction, + vec![InputAccountIdentity::Public, InputAccountIdentity::Public], + &program_with_deps, + ) + .context("Failed to execute/prove bridge deposit")?; + + // Create privacy-preserving transaction from circuit output + let message = privacy_preserving_transaction::Message::try_from_circuit_output( + vec![bridge_account_id, recipient_vault_id], + vec![bridge_pre.account.nonce, vault_pre.account.nonce], + vec![], + output, + ) + .context("Failed to build privacy-preserving bridge deposit message")?; + + let witness_set = privacy_preserving_transaction::WitnessSet::for_message(&message, proof, &[]); + let attack_tx = LeeTransaction::PrivacyPreserving(lee::PrivacyPreservingTransaction::new( + message, + witness_set, + )); + + let bridge_balance_before = ctx + .sequencer_client() + .get_account_balance(bridge_account_id) + .await?; + let vault_balance_before = ctx + .sequencer_client() + .get_account_balance(recipient_vault_id) + .await?; + + let tx_hash = ctx.sequencer_client().send_transaction(attack_tx).await?; + + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let bridge_balance_after = ctx + .sequencer_client() + .get_account_balance(bridge_account_id) + .await?; + let vault_balance_after = ctx + .sequencer_client() + .get_account_balance(recipient_vault_id) + .await?; + let tx_on_chain = ctx.sequencer_client().get_transaction(tx_hash).await?; + + assert_eq!(bridge_balance_after, bridge_balance_before); + assert_eq!(vault_balance_after, vault_balance_before); + assert!( + tx_on_chain.is_none(), + "Privacy-preserving bridge::Deposit invocation should be rejected" + ); + + Ok(()) +} + +async fn submit_bedrock_deposit( + bedrock_addr: std::net::SocketAddr, + recipient_id: AccountId, + amount: u128, +) -> anyhow::Result<()> { + #[derive(BorshSerialize)] + struct DepositMetadata { + recipient_id: AccountId, + } + + // Encode deposit metadata + let metadata = borsh::to_vec(&DepositMetadata { recipient_id }) + .context("Failed to encode deposit metadata")? + .try_into() + .context("Encoded metadata is too big")?; + + let funding_key = "2e03b2eff5a45478e7e79668d2a146cf2c5c7925bce927f2b1c67f2ab4fc0d26"; + + let amount: Value = amount + .try_into() + .context("Deposit amount does not fit Bedrock Value type")?; + let channel_id = integration_tests::config::bedrock_channel_id(); + let client = reqwest::Client::new(); + + let query_balance = || async { + let balance_response = client + .get(format!( + "http://{bedrock_addr}/wallet/{funding_key}/balance" + )) + .send() + .await + .context("Failed to query Bedrock wallet balance")?; + + let balance_response = check_response_success(balance_response).await?; + + balance_response + .json::() + .await + .context("Failed to decode Bedrock balance response") + }; + + let mut balance = query_balance().await?; + + info!( + "Queried Bedrock balance for key {funding_key}: {:?}", + balance.balance + ); + + if balance.balance < amount { + anyhow::bail!( + "Bedrock wallet with key {funding_key} has insufficient balance {:?} for deposit amount {:?}", + balance.balance, + amount + ); + } + + let mut selected_note_id = balance + .notes + .iter() + .find_map(|(note_id, value)| (*value == amount).then_some(*note_id)); + + if selected_note_id.is_none() { + let transfer_body = WalletTransferFundsRequestBody { + tip: None, + change_public_key: balance.address, + funding_public_keys: vec![balance.address], + recipient_public_key: balance.address, + amount, + }; + + let transfer_response = client + .post(format!( + "http://{bedrock_addr}/wallet/transactions/transfer-funds" + )) + .json(&transfer_body) + .send() + .await + .context("Failed to submit Bedrock transfer-funds request")?; + let transfer_response = check_response_success(transfer_response).await?; + + let transfer: WalletTransferFundsResponseBody = transfer_response + .json() + .await + .context("Failed to decode Bedrock transfer-funds response")?; + + info!( + "Submitted transfer-funds to create exact deposit note, tx hash {:?}", + transfer.hash + ); + + let mut found_note = None; + for _ in 0..20 { + tokio::time::sleep(Duration::from_millis(500)).await; + balance = query_balance().await?; + found_note = balance + .notes + .iter() + .find_map(|(note_id, value)| (*value == amount).then_some(*note_id)); + if found_note.is_some() { + break; + } + } + + selected_note_id = found_note; + } + + let Some(selected_note_id) = selected_note_id else { + anyhow::bail!( + "Failed to locate exact-value note {amount:?} for Bedrock deposit; available notes: {:?}", + balance.notes, + ); + }; + + let body = ChannelDepositRequestBody { + tip: None, + deposit: DepositOp { + channel_id, + inputs: Inputs::new(selected_note_id), + metadata, + }, + change_public_key: balance.address, + funding_public_keys: vec![balance.address], + max_tx_fee: 1_000_u64.into(), + }; + + let response = client + .post(format!("http://{bedrock_addr}/channel/deposit")) + .json(&body) + .send() + .await + .context("Failed to submit Bedrock deposit request")?; + let response = check_response_success(response).await?; + + let body_text = response + .text() + .await + .unwrap_or_else(|_| "".to_owned()); + info!( + "Successfully submitted Bedrock deposit request for recipient {recipient_id} and amount {amount}, response body: {body_text}", + ); + + Ok(()) +} + +async fn check_response_success(response: reqwest::Response) -> anyhow::Result { + if response.status().is_success() { + Ok(response) + } else { + let status = response.status(); + let body_text = response.text().await.unwrap_or_default(); + anyhow::bail!("Request failed with status {status} and body {body_text}"); + } +} + +async fn wait_for_vault_balance( + ctx: &TestContext, + vault_id: AccountId, + expected_balance: u128, +) -> anyhow::Result<()> { + let timeout = TIME_TO_FINALIZE_DEPOSIT_EVENT_ON_BEDROCK + + Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS); + tokio::time::timeout(timeout, async { + loop { + let balance = ctx.sequencer_client().get_account_balance(vault_id).await?; + if balance == expected_balance { + return Ok(()); + } + tokio::time::sleep(Duration::from_millis(500)).await; + } + }) + .await + .with_context(|| { + format!("Timed out waiting for vault {vault_id} balance to reach {expected_balance}") + })? +} + +#[test] +async fn bedrock_deposit_mints_to_vault_then_claim_succeeds() -> anyhow::Result<()> { + let ctx = TestContext::new().await?; + + let recipient_id = ctx.existing_public_accounts()[0]; + let vault_program_id = Program::vault().id(); + let recipient_vault_id = vault_core::compute_vault_account_id(vault_program_id, recipient_id); + + let vault_balance_before = ctx + .sequencer_client() + .get_account_balance(recipient_vault_id) + .await?; + let recipient_balance_before = ctx + .sequencer_client() + .get_account_balance(recipient_id) + .await?; + + // Submit deposit to Bedrock + submit_bedrock_deposit(ctx.bedrock_addr(), recipient_id, 1).await?; + + // Wait for vault to receive the deposit (minted from bridge to vault) + wait_for_vault_balance(&ctx, recipient_vault_id, vault_balance_before + 1).await?; + + // Now claim funds from vault back to recipient + let nonces = ctx + .wallet() + .get_accounts_nonces(vec![recipient_id]) + .await + .context("Failed to get nonce for vault claim")?; + + let signing_key = ctx + .wallet() + .storage() + .key_chain() + .pub_account_signing_key(recipient_id) + .with_context(|| format!("Missing signing key for account {recipient_id}"))?; + + let claim_message = public_transaction::Message::try_new( + vault_program_id, + vec![recipient_id, recipient_vault_id], + nonces, + vault_core::Instruction::Claim { amount: 1 }, + ) + .context("Failed to build vault claim message")?; + + let claim_witness_set = + public_transaction::WitnessSet::for_message(&claim_message, &[signing_key]); + let claim_tx = LeeTransaction::Public(lee::PublicTransaction::new( + claim_message, + claim_witness_set, + )); + + let claim_hash = ctx.sequencer_client().send_transaction(claim_tx).await?; + + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let claim_on_chain = ctx.sequencer_client().get_transaction(claim_hash).await?; + let vault_balance_after_claim = ctx + .sequencer_client() + .get_account_balance(recipient_vault_id) + .await?; + let recipient_balance_after_claim = ctx + .sequencer_client() + .get_account_balance(recipient_id) + .await?; + + assert!( + claim_on_chain.is_some(), + "Vault claim transaction must be included on-chain" + ); + assert_eq!( + vault_balance_after_claim, vault_balance_before, + "Vault balance should return to initial state after claim" + ); + assert_eq!( + recipient_balance_after_claim, + recipient_balance_before + 1, + "Recipient balance should increase by claimed amount" + ); + + Ok(()) +} diff --git a/integration_tests/tests/indexer.rs b/integration_tests/tests/indexer.rs deleted file mode 100644 index 5cf33cde..00000000 --- a/integration_tests/tests/indexer.rs +++ /dev/null @@ -1,279 +0,0 @@ -#![expect( - clippy::shadow_unrelated, - clippy::tests_outside_test_module, - reason = "We don't care about these in tests" -)] - -use std::time::Duration; - -use anyhow::{Context as _, Result}; -use indexer_service_rpc::RpcClient as _; -use integration_tests::{ - TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, private_mention, public_mention, - verify_commitment_is_in_state, -}; -use log::info; -use nssa::AccountId; -use wallet::{ - account::Label, - cli::{CliAccountMention, Command, programs::native_token_transfer::AuthTransferSubcommand}, -}; - -/// Maximum time to wait for the indexer to catch up to the sequencer. -const L2_TO_L1_TIMEOUT_MILLIS: u64 = 180_000; - -/// Poll the indexer until its last finalized block id reaches the sequencer's -/// current last block id or until [`L2_TO_L1_TIMEOUT_MILLIS`] elapses. -/// Returns the last indexer block id observed. -async fn wait_for_indexer_to_catch_up(ctx: &TestContext) -> Result { - let timeout = Duration::from_millis(L2_TO_L1_TIMEOUT_MILLIS); - let block_id_to_catch_up = - sequencer_service_rpc::RpcClient::get_last_block_id(ctx.sequencer_client()).await?; - let mut last_ind: u64 = 1; - let inner = async { - loop { - let ind = ctx - .indexer_client() - .get_last_finalized_block_id() - .await? - .unwrap_or(0); - last_ind = ind; - if ind >= block_id_to_catch_up { - let last_seq = - sequencer_service_rpc::RpcClient::get_last_block_id(ctx.sequencer_client()) - .await?; - info!( - "Indexer caught up. Indexer last block id: {ind}. Current sequencer last block id: {last_seq}" - ); - return Ok(ind); - } - tokio::time::sleep(Duration::from_secs(2)).await; - } - }; - tokio::time::timeout(timeout, inner) - .await - .with_context(|| { - format!( - "Indexer failed to catch up within {L2_TO_L1_TIMEOUT_MILLIS} milliseconds. Last indexer block id observed: {last_ind}, but needed to catch up to at least {block_id_to_catch_up}" - ) - })? -} - -#[tokio::test] -async fn indexer_test_run() -> Result<()> { - let ctx = TestContext::new().await?; - - let last_block_indexer = wait_for_indexer_to_catch_up(&ctx).await?; - - let last_block_seq = - sequencer_service_rpc::RpcClient::get_last_block_id(ctx.sequencer_client()).await?; - - info!("Last block on seq now is {last_block_seq}"); - info!("Last block on ind now is {last_block_indexer}"); - - assert!(last_block_indexer > 0); - - Ok(()) -} - -#[tokio::test] -async fn indexer_block_batching() -> Result<()> { - let ctx = TestContext::new().await?; - - info!("Waiting for indexer to parse blocks"); - let last_block_indexer = wait_for_indexer_to_catch_up(&ctx).await?; - - info!("Last block on ind now is {last_block_indexer}"); - - assert!(last_block_indexer > 0); - - // Getting wide batch to fit all blocks (from latest backwards) - let mut block_batch = ctx.indexer_client().get_blocks(None, 100).await.unwrap(); - - // Reverse to check chain consistency from oldest to newest - block_batch.reverse(); - - // Checking chain consistency - let mut prev_block_hash = block_batch.first().unwrap().header.hash; - - for block in &block_batch[1..] { - assert_eq!(block.header.prev_block_hash, prev_block_hash); - - info!("Block {} chain-consistent", block.header.block_id); - - prev_block_hash = block.header.hash; - } - - Ok(()) -} - -#[tokio::test] -async fn indexer_state_consistency() -> Result<()> { - let mut ctx = TestContext::new().await?; - - let command = Command::AuthTransfer(AuthTransferSubcommand::Send { - from: public_mention(ctx.existing_public_accounts()[0]), - to: Some(public_mention(ctx.existing_public_accounts()[1])), - to_npk: None, - to_vpk: None, - to_identifier: Some(0), - amount: 100, - }); - - wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; - - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - info!("Checking correct balance move"); - let acc_1_balance = sequencer_service_rpc::RpcClient::get_account_balance( - ctx.sequencer_client(), - ctx.existing_public_accounts()[0], - ) - .await?; - let acc_2_balance = sequencer_service_rpc::RpcClient::get_account_balance( - ctx.sequencer_client(), - ctx.existing_public_accounts()[1], - ) - .await?; - - info!("Balance of sender: {acc_1_balance:#?}"); - info!("Balance of receiver: {acc_2_balance:#?}"); - - assert_eq!(acc_1_balance, 9900); - assert_eq!(acc_2_balance, 20100); - - let from: AccountId = ctx.existing_private_accounts()[0]; - let to: AccountId = ctx.existing_private_accounts()[1]; - - let command = Command::AuthTransfer(AuthTransferSubcommand::Send { - from: private_mention(from), - to: Some(private_mention(to)), - to_npk: None, - to_vpk: None, - to_identifier: Some(0), - amount: 100, - }); - - wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; - - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - let new_commitment1 = ctx - .wallet() - .get_private_account_commitment(from) - .context("Failed to get private account commitment for sender")?; - assert!(verify_commitment_is_in_state(new_commitment1, ctx.sequencer_client()).await); - - let new_commitment2 = ctx - .wallet() - .get_private_account_commitment(to) - .context("Failed to get private account commitment for receiver")?; - assert!(verify_commitment_is_in_state(new_commitment2, ctx.sequencer_client()).await); - - info!("Successfully transferred privately to owned account"); - - info!("Waiting for indexer to parse blocks"); - wait_for_indexer_to_catch_up(&ctx).await?; - - let acc1_ind_state = ctx - .indexer_client() - .get_account(ctx.existing_public_accounts()[0].into()) - .await - .unwrap(); - let acc2_ind_state = ctx - .indexer_client() - .get_account(ctx.existing_public_accounts()[1].into()) - .await - .unwrap(); - - info!("Checking correct state transition"); - let acc1_seq_state = sequencer_service_rpc::RpcClient::get_account( - ctx.sequencer_client(), - ctx.existing_public_accounts()[0], - ) - .await?; - let acc2_seq_state = sequencer_service_rpc::RpcClient::get_account( - ctx.sequencer_client(), - ctx.existing_public_accounts()[1], - ) - .await?; - - assert_eq!(acc1_ind_state, acc1_seq_state.into()); - assert_eq!(acc2_ind_state, acc2_seq_state.into()); - - // ToDo: Check private state transition - - Ok(()) -} - -#[tokio::test] -async fn indexer_state_consistency_with_labels() -> Result<()> { - let mut ctx = TestContext::new().await?; - - // Assign labels to both accounts - let from_label = Label::new("idx-sender-label"); - let to_label = Label::new("idx-receiver-label"); - - let label_cmd = Command::Account(wallet::cli::account::AccountSubcommand::Label { - account_id: public_mention(ctx.existing_public_accounts()[0]), - label: from_label.clone(), - }); - wallet::cli::execute_subcommand(ctx.wallet_mut(), label_cmd).await?; - - let label_cmd = Command::Account(wallet::cli::account::AccountSubcommand::Label { - account_id: public_mention(ctx.existing_public_accounts()[1]), - label: to_label.clone(), - }); - wallet::cli::execute_subcommand(ctx.wallet_mut(), label_cmd).await?; - - // Send using labels instead of account IDs - let command = Command::AuthTransfer(AuthTransferSubcommand::Send { - from: CliAccountMention::Label(from_label), - to: Some(CliAccountMention::Label(to_label)), - to_npk: None, - to_vpk: None, - to_identifier: Some(0), - amount: 100, - }); - - wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; - - info!("Waiting for next block creation"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - - let acc_1_balance = sequencer_service_rpc::RpcClient::get_account_balance( - ctx.sequencer_client(), - ctx.existing_public_accounts()[0], - ) - .await?; - let acc_2_balance = sequencer_service_rpc::RpcClient::get_account_balance( - ctx.sequencer_client(), - ctx.existing_public_accounts()[1], - ) - .await?; - - assert_eq!(acc_1_balance, 9900); - assert_eq!(acc_2_balance, 20100); - - info!("Waiting for indexer to parse blocks"); - wait_for_indexer_to_catch_up(&ctx).await?; - - let acc1_ind_state = ctx - .indexer_client() - .get_account(ctx.existing_public_accounts()[0].into()) - .await - .unwrap(); - let acc1_seq_state = sequencer_service_rpc::RpcClient::get_account( - ctx.sequencer_client(), - ctx.existing_public_accounts()[0], - ) - .await?; - - assert_eq!(acc1_ind_state, acc1_seq_state.into()); - - info!("Indexer state is consistent after label-based transfer"); - - Ok(()) -} diff --git a/integration_tests/tests/indexer_block_batching.rs b/integration_tests/tests/indexer_block_batching.rs new file mode 100644 index 00000000..d5999f10 --- /dev/null +++ b/integration_tests/tests/indexer_block_batching.rs @@ -0,0 +1,40 @@ +#![expect( + clippy::tests_outside_test_module, + reason = "We don't care about these in tests" +)] + +use anyhow::Result; +use indexer_service_rpc::RpcClient as _; +use integration_tests::{TestContext, wait_for_indexer_to_catch_up}; +use log::info; + +#[tokio::test] +async fn indexer_block_batching() -> Result<()> { + let ctx = TestContext::new().await?; + + info!("Waiting for indexer to parse blocks"); + let last_block_indexer = wait_for_indexer_to_catch_up(&ctx).await?; + + info!("Last block on ind now is {last_block_indexer}"); + + assert!(last_block_indexer > 0); + + // Getting wide batch to fit all blocks (from latest backwards) + let mut block_batch = ctx.indexer_client().get_blocks(None, 100).await.unwrap(); + + // Reverse to check chain consistency from oldest to newest + block_batch.reverse(); + + // Checking chain consistency + let mut prev_block_hash = block_batch.first().unwrap().header.hash; + + for block in &block_batch[1..] { + assert_eq!(block.header.prev_block_hash, prev_block_hash); + + info!("Block {} chain-consistent", block.header.block_id); + + prev_block_hash = block.header.hash; + } + + Ok(()) +} diff --git a/integration_tests/tests/indexer_ffi.rs b/integration_tests/tests/indexer_ffi.rs deleted file mode 100644 index 178b2640..00000000 --- a/integration_tests/tests/indexer_ffi.rs +++ /dev/null @@ -1,403 +0,0 @@ -#![expect( - clippy::shadow_unrelated, - clippy::tests_outside_test_module, - clippy::undocumented_unsafe_blocks, - reason = "We don't care about these in tests" -)] - -use std::{ - ffi::{CString, c_char}, - fs::File, - io::Write as _, - net::SocketAddr, -}; - -use anyhow::{Context as _, Result}; -use indexer_ffi::{ - IndexerServiceFFI, OperationStatus, Runtime, - api::{ - PointerResult, - lifecycle::InitializedIndexerServiceFFIResult, - types::{FfiAccountId, FfiOption, FfiVec, account::FfiAccount, block::FfiBlock}, - }, -}; -use integration_tests::{ - BlockingTestContext, TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, private_mention, - public_mention, verify_commitment_is_in_state, -}; -use log::{debug, info}; -use nssa::AccountId; -use tempfile::TempDir; -use wallet::{ - account::Label, - cli::{Command, programs::native_token_transfer::AuthTransferSubcommand}, -}; - -/// Maximum time to wait for the indexer to catch up to the sequencer. -const L2_TO_L1_TIMEOUT_MILLIS: u64 = 180_000; - -unsafe extern "C" { - unsafe fn query_last_block( - runtime: *const Runtime, - indexer: *const IndexerServiceFFI, - ) -> PointerResult; - - unsafe fn query_block_vec( - runtime: *const Runtime, - indexer: *const IndexerServiceFFI, - before: FfiOption, - limit: u64, - ) -> PointerResult, OperationStatus>; - - unsafe fn query_account( - runtime: *const Runtime, - indexer: *const IndexerServiceFFI, - account_id: FfiAccountId, - ) -> PointerResult; - - unsafe fn start_indexer( - runtime: *const Runtime, - config_path: *const c_char, - port: u16, - ) -> InitializedIndexerServiceFFIResult; -} - -fn setup_indexer_ffi( - runtime: &Runtime, - bedrock_addr: SocketAddr, -) -> Result<(IndexerServiceFFI, TempDir)> { - let temp_indexer_dir = - tempfile::tempdir().context("Failed to create temp dir for indexer home")?; - - debug!( - "Using temp indexer home at {}", - temp_indexer_dir.path().display() - ); - - let indexer_config = - integration_tests::config::indexer_config(bedrock_addr, temp_indexer_dir.path().to_owned()) - .context("Failed to create Indexer config")?; - - let config_json = serde_json::to_vec(&indexer_config)?; - let config_path = temp_indexer_dir.path().join("indexer_config.json"); - let mut file = File::create(config_path.as_path())?; - file.write_all(&config_json)?; - file.flush()?; - - let res = - // SAFETY: lib function ensures validity of value. - unsafe { start_indexer(std::ptr::from_ref(runtime), CString::new(config_path.to_str().unwrap())?.as_ptr(), 0) }; - - if res.error.is_error() { - anyhow::bail!("Indexer FFI error {:?}", res.error); - } - - Ok(( - // SAFETY: lib function ensures validity of value. - unsafe { std::ptr::read(res.value) }, - temp_indexer_dir, - )) -} - -/// Prepare setup for tests. -fn setup() -> Result<(BlockingTestContext, IndexerServiceFFI, TempDir)> { - let ctx = TestContext::builder().disable_indexer().build_blocking()?; - // Safety: ctx runtime is valid for the lifetime of the returned Runtime - let runtime = unsafe { Runtime::from_borrowed(ctx.runtime()) }; - let (indexer_ffi, indexer_dir) = setup_indexer_ffi(&runtime, ctx.ctx().bedrock_addr())?; - - Ok((ctx, indexer_ffi, indexer_dir)) -} - -#[test] -fn indexer_test_run_ffi() -> Result<()> { - let (ctx, indexer_ffi, _indexer_dir) = setup()?; - - // RUN OBSERVATION - std::thread::sleep(std::time::Duration::from_millis(L2_TO_L1_TIMEOUT_MILLIS)); - - // Safety: ctx runtime is valid for the lifetime of the returned Runtime - let runtime = unsafe { Runtime::from_borrowed(ctx.runtime()) }; - let last_block_indexer_ffi_res = - unsafe { query_last_block(&raw const runtime, &raw const indexer_ffi) }; - - assert!(last_block_indexer_ffi_res.error.is_ok()); - - let last_block_indexer_ffi = unsafe { *last_block_indexer_ffi_res.value }; - - info!("Last block on indexer FFI now is {last_block_indexer_ffi}"); - - assert!(last_block_indexer_ffi > 0); - - Ok(()) -} - -#[test] -fn indexer_ffi_block_batching() -> Result<()> { - let (ctx, indexer_ffi, _indexer_dir) = setup()?; - - // WAIT - info!("Waiting for indexer to parse blocks"); - std::thread::sleep(std::time::Duration::from_millis(L2_TO_L1_TIMEOUT_MILLIS)); - - // Safety: ctx runtime is valid for the lifetime of the returned Runtime - let runtime = unsafe { Runtime::from_borrowed(ctx.runtime()) }; - let last_block_indexer_ffi_res = - unsafe { query_last_block(&raw const runtime, &raw const indexer_ffi) }; - - assert!(last_block_indexer_ffi_res.error.is_ok()); - - let last_block_indexer = unsafe { *last_block_indexer_ffi_res.value }; - - info!("Last block on indexer FFI now is {last_block_indexer}"); - - assert!(last_block_indexer > 0); - - let before_ffi = FfiOption::::from_none(); - let limit = 100; - - let block_batch_ffi_res = unsafe { - query_block_vec( - &raw const runtime, - &raw const indexer_ffi, - before_ffi, - limit, - ) - }; - - assert!(block_batch_ffi_res.error.is_ok()); - - let block_batch = unsafe { &*block_batch_ffi_res.value }; - - let mut last_block_prev_hash = unsafe { block_batch.get(0) }.header.prev_block_hash.data; - - for i in 1..block_batch.len { - let block = unsafe { block_batch.get(i) }; - - assert_eq!(last_block_prev_hash, block.header.hash.data); - - info!("Block {} chain-consistent", block.header.block_id); - - last_block_prev_hash = block.header.prev_block_hash.data; - } - - Ok(()) -} - -#[test] -fn indexer_ffi_state_consistency() -> Result<()> { - let (mut ctx, indexer_ffi, _indexer_dir) = setup()?; - - let command = Command::AuthTransfer(AuthTransferSubcommand::Send { - from: public_mention(ctx.ctx().existing_public_accounts()[0]), - to: Some(public_mention(ctx.ctx().existing_public_accounts()[1])), - to_npk: None, - to_vpk: None, - amount: 100, - to_identifier: Some(0), - }); - - ctx.block_on_mut(|ctx| wallet::cli::execute_subcommand(ctx.wallet_mut(), command))?; - - info!("Waiting for next block creation"); - std::thread::sleep(std::time::Duration::from_secs( - TIME_TO_WAIT_FOR_BLOCK_SECONDS, - )); - - info!("Checking correct balance move"); - let acc_1_balance = ctx.block_on(|ctx| { - sequencer_service_rpc::RpcClient::get_account_balance( - ctx.sequencer_client(), - ctx.existing_public_accounts()[0], - ) - })?; - let acc_2_balance = ctx.block_on(|ctx| { - sequencer_service_rpc::RpcClient::get_account_balance( - ctx.sequencer_client(), - ctx.existing_public_accounts()[1], - ) - })?; - - info!("Balance of sender: {acc_1_balance:#?}"); - info!("Balance of receiver: {acc_2_balance:#?}"); - - assert_eq!(acc_1_balance, 9900); - assert_eq!(acc_2_balance, 20100); - - let from: AccountId = ctx.ctx().existing_private_accounts()[0]; - let to: AccountId = ctx.ctx().existing_private_accounts()[1]; - - let command = Command::AuthTransfer(AuthTransferSubcommand::Send { - from: private_mention(from), - to: Some(private_mention(to)), - to_npk: None, - to_vpk: None, - amount: 100, - to_identifier: Some(0), - }); - - ctx.block_on_mut(|ctx| wallet::cli::execute_subcommand(ctx.wallet_mut(), command))?; - - info!("Waiting for next block creation"); - std::thread::sleep(std::time::Duration::from_secs( - TIME_TO_WAIT_FOR_BLOCK_SECONDS, - )); - - let new_commitment1 = ctx - .ctx() - .wallet() - .get_private_account_commitment(from) - .context("Failed to get private account commitment for sender")?; - let commitment_check1 = - ctx.block_on(|ctx| verify_commitment_is_in_state(new_commitment1, ctx.sequencer_client())); - assert!(commitment_check1); - - let new_commitment2 = ctx - .ctx() - .wallet() - .get_private_account_commitment(to) - .context("Failed to get private account commitment for receiver")?; - let commitment_check2 = - ctx.block_on(|ctx| verify_commitment_is_in_state(new_commitment2, ctx.sequencer_client())); - assert!(commitment_check2); - - info!("Successfully transferred privately to owned account"); - - // WAIT - info!("Waiting for indexer to parse blocks"); - std::thread::sleep(std::time::Duration::from_millis(L2_TO_L1_TIMEOUT_MILLIS)); - - // Safety: ctx runtime is valid for the lifetime of the returned Runtime - let runtime = unsafe { Runtime::from_borrowed(ctx.runtime()) }; - let acc1_ind_state_ffi = unsafe { - query_account( - &raw const runtime, - &raw const indexer_ffi, - (&ctx.ctx().existing_public_accounts()[0]).into(), - ) - }; - - assert!(acc1_ind_state_ffi.error.is_ok()); - - let acc1_ind_state_pre = unsafe { &*acc1_ind_state_ffi.value }; - let acc1_ind_state: indexer_service_protocol::Account = acc1_ind_state_pre.into(); - - let acc2_ind_state_ffi = unsafe { - query_account( - &raw const runtime, - &raw const indexer_ffi, - (&ctx.ctx().existing_public_accounts()[1]).into(), - ) - }; - - assert!(acc2_ind_state_ffi.error.is_ok()); - - let acc2_ind_state_pre = unsafe { &*acc2_ind_state_ffi.value }; - let acc2_ind_state: indexer_service_protocol::Account = acc2_ind_state_pre.into(); - - info!("Checking correct state transition"); - let acc1_seq_state = ctx.block_on(|ctx| { - sequencer_service_rpc::RpcClient::get_account( - ctx.sequencer_client(), - ctx.existing_public_accounts()[0], - ) - })?; - let acc2_seq_state = ctx.block_on(|ctx| { - sequencer_service_rpc::RpcClient::get_account( - ctx.sequencer_client(), - ctx.existing_public_accounts()[1], - ) - })?; - - assert_eq!(acc1_ind_state, acc1_seq_state.into()); - assert_eq!(acc2_ind_state, acc2_seq_state.into()); - - // ToDo: Check private state transition - - Ok(()) -} - -#[test] -fn indexer_ffi_state_consistency_with_labels() -> Result<()> { - let (mut ctx, indexer_ffi, _indexer_dir) = setup()?; - - // Assign labels to both accounts - let from_label = Label::new("idx-sender-label"); - let to_label = Label::new("idx-receiver-label"); - - let label_cmd = Command::Account(wallet::cli::account::AccountSubcommand::Label { - account_id: public_mention(ctx.ctx().existing_public_accounts()[0]), - label: from_label.clone(), - }); - ctx.block_on_mut(|ctx| wallet::cli::execute_subcommand(ctx.wallet_mut(), label_cmd))?; - - let label_cmd = Command::Account(wallet::cli::account::AccountSubcommand::Label { - account_id: public_mention(ctx.ctx().existing_public_accounts()[1]), - label: to_label.clone(), - }); - ctx.block_on_mut(|ctx| wallet::cli::execute_subcommand(ctx.wallet_mut(), label_cmd))?; - - // Send using labels instead of account IDs - let command = Command::AuthTransfer(AuthTransferSubcommand::Send { - from: from_label.into(), - to: Some(to_label.into()), - to_npk: None, - to_vpk: None, - amount: 100, - to_identifier: Some(0), - }); - - ctx.block_on_mut(|ctx| wallet::cli::execute_subcommand(ctx.wallet_mut(), command))?; - - info!("Waiting for next block creation"); - std::thread::sleep(std::time::Duration::from_secs( - TIME_TO_WAIT_FOR_BLOCK_SECONDS, - )); - - let acc_1_balance = ctx.block_on(|ctx| { - sequencer_service_rpc::RpcClient::get_account_balance( - ctx.sequencer_client(), - ctx.existing_public_accounts()[0], - ) - })?; - let acc_2_balance = ctx.block_on(|ctx| { - sequencer_service_rpc::RpcClient::get_account_balance( - ctx.sequencer_client(), - ctx.existing_public_accounts()[1], - ) - })?; - - assert_eq!(acc_1_balance, 9900); - assert_eq!(acc_2_balance, 20100); - - info!("Waiting for indexer to parse blocks"); - std::thread::sleep(std::time::Duration::from_millis(L2_TO_L1_TIMEOUT_MILLIS)); - - // Safety: ctx runtime is valid for the lifetime of the returned Runtime - let runtime = unsafe { Runtime::from_borrowed(ctx.runtime()) }; - let acc1_ind_state_ffi = unsafe { - query_account( - &raw const runtime, - &raw const indexer_ffi, - (&ctx.ctx().existing_public_accounts()[0]).into(), - ) - }; - - assert!(acc1_ind_state_ffi.error.is_ok()); - - let acc1_ind_state_pre = unsafe { &*acc1_ind_state_ffi.value }; - let acc1_ind_state: indexer_service_protocol::Account = acc1_ind_state_pre.into(); - - let acc1_seq_state = ctx.block_on(|ctx| { - sequencer_service_rpc::RpcClient::get_account( - ctx.sequencer_client(), - ctx.existing_public_accounts()[0], - ) - })?; - - assert_eq!(acc1_ind_state, acc1_seq_state.into()); - - info!("Indexer state is consistent after label-based transfer"); - - Ok(()) -} diff --git a/integration_tests/tests/indexer_ffi_block_batching.rs b/integration_tests/tests/indexer_ffi_block_batching.rs new file mode 100644 index 00000000..eeef276d --- /dev/null +++ b/integration_tests/tests/indexer_ffi_block_batching.rs @@ -0,0 +1,66 @@ +#![expect( + clippy::tests_outside_test_module, + clippy::undocumented_unsafe_blocks, + reason = "We don't care about these in tests" +)] + +use anyhow::Result; +use indexer_ffi::{Runtime, api::types::FfiOption}; +use integration_tests::L2_TO_L1_TIMEOUT; +use log::info; + +#[path = "indexer_ffi_helpers/mod.rs"] +mod indexer_ffi_helpers; + +#[test] +fn indexer_ffi_block_batching() -> Result<()> { + let (ctx, indexer_ffi, _indexer_dir) = indexer_ffi_helpers::setup()?; + + // WAIT + info!("Waiting for indexer to parse blocks"); + std::thread::sleep(L2_TO_L1_TIMEOUT); + + // Safety: ctx runtime is valid for the lifetime of the returned Runtime + let runtime = unsafe { Runtime::from_borrowed(ctx.runtime()) }; + let last_block_indexer_ffi_res = unsafe { + indexer_ffi_helpers::query_last_block(&raw const runtime, &raw const indexer_ffi) + }; + + assert!(last_block_indexer_ffi_res.error.is_ok()); + + let last_block_indexer = unsafe { *last_block_indexer_ffi_res.value }; + + info!("Last block on indexer FFI now is {last_block_indexer}"); + + assert!(last_block_indexer > 0); + + let before_ffi = FfiOption::::from_none(); + let limit = 100; + + let block_batch_ffi_res = unsafe { + indexer_ffi_helpers::query_block_vec( + &raw const runtime, + &raw const indexer_ffi, + before_ffi, + limit, + ) + }; + + assert!(block_batch_ffi_res.error.is_ok()); + + let block_batch = unsafe { &*block_batch_ffi_res.value }; + + let mut last_block_prev_hash = unsafe { block_batch.get(0) }.header.prev_block_hash.data; + + for i in 1..block_batch.len { + let block = unsafe { block_batch.get(i) }; + + assert_eq!(last_block_prev_hash, block.header.hash.data); + + info!("Block {} chain-consistent", block.header.block_id); + + last_block_prev_hash = block.header.prev_block_hash.data; + } + + Ok(()) +} diff --git a/integration_tests/tests/indexer_ffi_helpers/mod.rs b/integration_tests/tests/indexer_ffi_helpers/mod.rs new file mode 100644 index 00000000..c3c3caff --- /dev/null +++ b/integration_tests/tests/indexer_ffi_helpers/mod.rs @@ -0,0 +1,91 @@ +#![allow(dead_code, reason = "helper module used only by FFI test binaries")] + +use std::{ + ffi::{CString, c_char}, + fs::File, + io::Write as _, + net::SocketAddr, +}; + +use anyhow::{Context as _, Result}; +use indexer_ffi::{ + IndexerServiceFFI, OperationStatus, Runtime, + api::{ + PointerResult, + lifecycle::InitializedIndexerServiceFFIResult, + types::{FfiAccountId, FfiOption, FfiVec, account::FfiAccount, block::FfiBlock}, + }, +}; +use integration_tests::{BlockingTestContext, TestContext}; +use tempfile::TempDir; + +unsafe extern "C" { + pub unsafe fn query_last_block( + runtime: *const Runtime, + indexer: *const IndexerServiceFFI, + ) -> PointerResult; + + pub unsafe fn query_block_vec( + runtime: *const Runtime, + indexer: *const IndexerServiceFFI, + before: FfiOption, + limit: u64, + ) -> PointerResult, OperationStatus>; + + pub unsafe fn query_account( + runtime: *const Runtime, + indexer: *const IndexerServiceFFI, + account_id: FfiAccountId, + ) -> PointerResult; + + pub unsafe fn start_indexer( + runtime: *const Runtime, + config_path: *const c_char, + port: u16, + ) -> InitializedIndexerServiceFFIResult; +} + +pub fn setup_indexer_ffi( + runtime: &Runtime, + bedrock_addr: SocketAddr, +) -> Result<(IndexerServiceFFI, TempDir)> { + let temp_indexer_dir = + tempfile::tempdir().context("Failed to create temp dir for indexer home")?; + + log::debug!( + "Using temp indexer home at {}", + temp_indexer_dir.path().display() + ); + + let indexer_config = + integration_tests::config::indexer_config(bedrock_addr, temp_indexer_dir.path().to_owned()) + .context("Failed to create Indexer config")?; + + let config_json = serde_json::to_vec(&indexer_config)?; + let config_path = temp_indexer_dir.path().join("indexer_config.json"); + let mut file = File::create(config_path.as_path())?; + file.write_all(&config_json)?; + file.flush()?; + + let res = + // SAFETY: lib function ensures validity of value. + unsafe { start_indexer(std::ptr::from_ref(runtime), CString::new(config_path.to_str().unwrap())?.as_ptr(), 0) }; + + if res.error.is_error() { + anyhow::bail!("Indexer FFI error {:?}", res.error); + } + + Ok(( + // SAFETY: lib function ensures validity of value. + unsafe { std::ptr::read(res.value) }, + temp_indexer_dir, + )) +} + +pub fn setup() -> Result<(BlockingTestContext, IndexerServiceFFI, TempDir)> { + let ctx = TestContext::builder().disable_indexer().build_blocking()?; + // Safety: ctx runtime is valid for the lifetime of the returned Runtime + let runtime = unsafe { Runtime::from_borrowed(ctx.runtime()) }; + let (indexer_ffi, indexer_dir) = setup_indexer_ffi(&runtime, ctx.ctx().bedrock_addr())?; + Ok((ctx, indexer_ffi, indexer_dir)) +} diff --git a/integration_tests/tests/indexer_ffi_state_consistency.rs b/integration_tests/tests/indexer_ffi_state_consistency.rs new file mode 100644 index 00000000..f84a3790 --- /dev/null +++ b/integration_tests/tests/indexer_ffi_state_consistency.rs @@ -0,0 +1,153 @@ +#![expect( + clippy::shadow_unrelated, + clippy::tests_outside_test_module, + clippy::undocumented_unsafe_blocks, + reason = "We don't care about these in tests" +)] + +use std::time::Duration; + +use anyhow::{Context as _, Result}; +use indexer_ffi::Runtime; +use indexer_service_protocol::Account; +use integration_tests::{ + L2_TO_L1_TIMEOUT, TIME_TO_WAIT_FOR_BLOCK_SECONDS, private_mention, public_mention, + verify_commitment_is_in_state, +}; +use lee::AccountId; +use log::info; +use wallet::cli::{Command, programs::native_token_transfer::AuthTransferSubcommand}; + +#[path = "indexer_ffi_helpers/mod.rs"] +mod indexer_ffi_helpers; + +#[test] +fn indexer_ffi_state_consistency() -> Result<()> { + let (mut ctx, indexer_ffi, _indexer_dir) = indexer_ffi_helpers::setup()?; + + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: public_mention(ctx.ctx().existing_public_accounts()[0]), + to: Some(public_mention(ctx.ctx().existing_public_accounts()[1])), + to_npk: None, + to_vpk: None, + to_keys: None, + amount: 100, + to_identifier: Some(0), + }); + + ctx.block_on_mut(|ctx| wallet::cli::execute_subcommand(ctx.wallet_mut(), command))?; + + info!("Waiting for next block creation"); + std::thread::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)); + + info!("Checking correct balance move"); + let acc_1_balance = ctx.block_on(|ctx| { + sequencer_service_rpc::RpcClient::get_account_balance( + ctx.sequencer_client(), + ctx.existing_public_accounts()[0], + ) + })?; + let acc_2_balance = ctx.block_on(|ctx| { + sequencer_service_rpc::RpcClient::get_account_balance( + ctx.sequencer_client(), + ctx.existing_public_accounts()[1], + ) + })?; + + info!("Balance of sender: {acc_1_balance:#?}"); + info!("Balance of receiver: {acc_2_balance:#?}"); + + assert_eq!(acc_1_balance, 9900); + assert_eq!(acc_2_balance, 20100); + + let from: AccountId = ctx.ctx().existing_private_accounts()[0]; + let to: AccountId = ctx.ctx().existing_private_accounts()[1]; + + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: private_mention(from), + to: Some(private_mention(to)), + to_npk: None, + to_vpk: None, + to_keys: None, + amount: 100, + to_identifier: Some(0), + }); + + ctx.block_on_mut(|ctx| wallet::cli::execute_subcommand(ctx.wallet_mut(), command))?; + + info!("Waiting for next block creation"); + std::thread::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)); + + let new_commitment1 = ctx + .ctx() + .wallet() + .get_private_account_commitment(from) + .context("Failed to get private account commitment for sender")?; + let commitment_check1 = + ctx.block_on(|ctx| verify_commitment_is_in_state(new_commitment1, ctx.sequencer_client())); + assert!(commitment_check1); + + let new_commitment2 = ctx + .ctx() + .wallet() + .get_private_account_commitment(to) + .context("Failed to get private account commitment for receiver")?; + let commitment_check2 = + ctx.block_on(|ctx| verify_commitment_is_in_state(new_commitment2, ctx.sequencer_client())); + assert!(commitment_check2); + + info!("Successfully transferred privately to owned account"); + + // WAIT + info!("Waiting for indexer to parse blocks"); + std::thread::sleep(L2_TO_L1_TIMEOUT); + + // Safety: ctx runtime is valid for the lifetime of the returned Runtime + let runtime = unsafe { Runtime::from_borrowed(ctx.runtime()) }; + let acc1_ind_state_ffi = unsafe { + indexer_ffi_helpers::query_account( + &raw const runtime, + &raw const indexer_ffi, + (&ctx.ctx().existing_public_accounts()[0]).into(), + ) + }; + + assert!(acc1_ind_state_ffi.error.is_ok()); + + let acc1_ind_state_pre = unsafe { &*acc1_ind_state_ffi.value }; + let acc1_ind_state: Account = acc1_ind_state_pre.into(); + + let acc2_ind_state_ffi = unsafe { + indexer_ffi_helpers::query_account( + &raw const runtime, + &raw const indexer_ffi, + (&ctx.ctx().existing_public_accounts()[1]).into(), + ) + }; + + assert!(acc2_ind_state_ffi.error.is_ok()); + + let acc2_ind_state_pre = unsafe { &*acc2_ind_state_ffi.value }; + let acc2_ind_state: Account = acc2_ind_state_pre.into(); + + info!("Checking correct state transition"); + let acc1_seq_state = ctx.block_on(|ctx| { + sequencer_service_rpc::RpcClient::get_account( + ctx.sequencer_client(), + ctx.existing_public_accounts()[0], + ) + })?; + let acc2_seq_state = ctx.block_on(|ctx| { + sequencer_service_rpc::RpcClient::get_account( + ctx.sequencer_client(), + ctx.existing_public_accounts()[1], + ) + })?; + + assert_eq!(acc1_ind_state, acc1_seq_state.into()); + assert_eq!(acc2_ind_state, acc2_seq_state.into()); + + // ToDo: Check private state transition + + Ok(()) +} diff --git a/integration_tests/tests/indexer_ffi_state_consistency_with_labels.rs b/integration_tests/tests/indexer_ffi_state_consistency_with_labels.rs new file mode 100644 index 00000000..34d5a4d7 --- /dev/null +++ b/integration_tests/tests/indexer_ffi_state_consistency_with_labels.rs @@ -0,0 +1,105 @@ +#![expect( + clippy::shadow_unrelated, + clippy::tests_outside_test_module, + clippy::undocumented_unsafe_blocks, + reason = "We don't care about these in tests" +)] + +use std::time::Duration; + +use anyhow::Result; +use indexer_ffi::Runtime; +use indexer_service_protocol::Account; +use integration_tests::{L2_TO_L1_TIMEOUT, TIME_TO_WAIT_FOR_BLOCK_SECONDS, public_mention}; +use log::info; +use wallet::{ + account::Label, + cli::{Command, programs::native_token_transfer::AuthTransferSubcommand}, +}; + +#[path = "indexer_ffi_helpers/mod.rs"] +mod indexer_ffi_helpers; + +#[test] +fn indexer_ffi_state_consistency_with_labels() -> Result<()> { + let (mut ctx, indexer_ffi, _indexer_dir) = indexer_ffi_helpers::setup()?; + + // Assign labels to both accounts + let from_label = Label::new("idx-sender-label"); + let to_label = Label::new("idx-receiver-label"); + + let label_cmd = Command::Account(wallet::cli::account::AccountSubcommand::Label { + account_id: public_mention(ctx.ctx().existing_public_accounts()[0]), + label: from_label.clone(), + }); + ctx.block_on_mut(|ctx| wallet::cli::execute_subcommand(ctx.wallet_mut(), label_cmd))?; + + let label_cmd = Command::Account(wallet::cli::account::AccountSubcommand::Label { + account_id: public_mention(ctx.ctx().existing_public_accounts()[1]), + label: to_label.clone(), + }); + ctx.block_on_mut(|ctx| wallet::cli::execute_subcommand(ctx.wallet_mut(), label_cmd))?; + + // Send using labels instead of account IDs + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: from_label.into(), + to: Some(to_label.into()), + to_npk: None, + to_vpk: None, + to_keys: None, + amount: 100, + to_identifier: Some(0), + }); + + ctx.block_on_mut(|ctx| wallet::cli::execute_subcommand(ctx.wallet_mut(), command))?; + + info!("Waiting for next block creation"); + std::thread::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)); + + let acc_1_balance = ctx.block_on(|ctx| { + sequencer_service_rpc::RpcClient::get_account_balance( + ctx.sequencer_client(), + ctx.existing_public_accounts()[0], + ) + })?; + let acc_2_balance = ctx.block_on(|ctx| { + sequencer_service_rpc::RpcClient::get_account_balance( + ctx.sequencer_client(), + ctx.existing_public_accounts()[1], + ) + })?; + + assert_eq!(acc_1_balance, 9900); + assert_eq!(acc_2_balance, 20100); + + info!("Waiting for indexer to parse blocks"); + std::thread::sleep(L2_TO_L1_TIMEOUT); + + // Safety: ctx runtime is valid for the lifetime of the returned Runtime + let runtime = unsafe { Runtime::from_borrowed(ctx.runtime()) }; + let acc1_ind_state_ffi = unsafe { + indexer_ffi_helpers::query_account( + &raw const runtime, + &raw const indexer_ffi, + (&ctx.ctx().existing_public_accounts()[0]).into(), + ) + }; + + assert!(acc1_ind_state_ffi.error.is_ok()); + + let acc1_ind_state_pre = unsafe { &*acc1_ind_state_ffi.value }; + let acc1_ind_state: Account = acc1_ind_state_pre.into(); + + let acc1_seq_state = ctx.block_on(|ctx| { + sequencer_service_rpc::RpcClient::get_account( + ctx.sequencer_client(), + ctx.existing_public_accounts()[0], + ) + })?; + + assert_eq!(acc1_ind_state, acc1_seq_state.into()); + + info!("Indexer state is consistent after label-based transfer"); + + Ok(()) +} diff --git a/integration_tests/tests/indexer_state_consistency.rs b/integration_tests/tests/indexer_state_consistency.rs new file mode 100644 index 00000000..e87927bc --- /dev/null +++ b/integration_tests/tests/indexer_state_consistency.rs @@ -0,0 +1,120 @@ +#![expect( + clippy::shadow_unrelated, + clippy::tests_outside_test_module, + reason = "We don't care about these in tests" +)] + +use std::time::Duration; + +use anyhow::{Context as _, Result}; +use indexer_service_rpc::RpcClient as _; +use integration_tests::{ + TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, private_mention, public_mention, + verify_commitment_is_in_state, wait_for_indexer_to_catch_up, +}; +use lee::AccountId; +use log::info; +use wallet::cli::{Command, programs::native_token_transfer::AuthTransferSubcommand}; + +#[tokio::test] +async fn indexer_state_consistency() -> Result<()> { + let mut ctx = TestContext::new().await?; + + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: public_mention(ctx.existing_public_accounts()[0]), + to: Some(public_mention(ctx.existing_public_accounts()[1])), + to_npk: None, + to_vpk: None, + to_keys: None, + to_identifier: Some(0), + amount: 100, + }); + + wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + info!("Checking correct balance move"); + let acc_1_balance = sequencer_service_rpc::RpcClient::get_account_balance( + ctx.sequencer_client(), + ctx.existing_public_accounts()[0], + ) + .await?; + let acc_2_balance = sequencer_service_rpc::RpcClient::get_account_balance( + ctx.sequencer_client(), + ctx.existing_public_accounts()[1], + ) + .await?; + + info!("Balance of sender: {acc_1_balance:#?}"); + info!("Balance of receiver: {acc_2_balance:#?}"); + + assert_eq!(acc_1_balance, 9900); + assert_eq!(acc_2_balance, 20100); + + let from: AccountId = ctx.existing_private_accounts()[0]; + let to: AccountId = ctx.existing_private_accounts()[1]; + + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: private_mention(from), + to: Some(private_mention(to)), + to_npk: None, + to_vpk: None, + to_keys: None, + to_identifier: Some(0), + amount: 100, + }); + + wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let new_commitment1 = ctx + .wallet() + .get_private_account_commitment(from) + .context("Failed to get private account commitment for sender")?; + assert!(verify_commitment_is_in_state(new_commitment1, ctx.sequencer_client()).await); + + let new_commitment2 = ctx + .wallet() + .get_private_account_commitment(to) + .context("Failed to get private account commitment for receiver")?; + assert!(verify_commitment_is_in_state(new_commitment2, ctx.sequencer_client()).await); + + info!("Successfully transferred privately to owned account"); + + info!("Waiting for indexer to parse blocks"); + wait_for_indexer_to_catch_up(&ctx).await?; + + let acc1_ind_state = ctx + .indexer_client() + .get_account(ctx.existing_public_accounts()[0].into()) + .await + .unwrap(); + let acc2_ind_state = ctx + .indexer_client() + .get_account(ctx.existing_public_accounts()[1].into()) + .await + .unwrap(); + + info!("Checking correct state transition"); + let acc1_seq_state = sequencer_service_rpc::RpcClient::get_account( + ctx.sequencer_client(), + ctx.existing_public_accounts()[0], + ) + .await?; + let acc2_seq_state = sequencer_service_rpc::RpcClient::get_account( + ctx.sequencer_client(), + ctx.existing_public_accounts()[1], + ) + .await?; + + assert_eq!(acc1_ind_state, acc1_seq_state.into()); + assert_eq!(acc2_ind_state, acc2_seq_state.into()); + + // ToDo: Check private state transition + + Ok(()) +} diff --git a/integration_tests/tests/indexer_state_consistency_with_labels.rs b/integration_tests/tests/indexer_state_consistency_with_labels.rs new file mode 100644 index 00000000..5f561d6f --- /dev/null +++ b/integration_tests/tests/indexer_state_consistency_with_labels.rs @@ -0,0 +1,89 @@ +#![expect( + clippy::shadow_unrelated, + clippy::tests_outside_test_module, + reason = "We don't care about these in tests" +)] + +use std::time::Duration; + +use anyhow::Result; +use indexer_service_rpc::RpcClient as _; +use integration_tests::{ + TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, public_mention, wait_for_indexer_to_catch_up, +}; +use log::info; +use wallet::{ + account::Label, + cli::{CliAccountMention, Command, programs::native_token_transfer::AuthTransferSubcommand}, +}; + +#[tokio::test] +async fn indexer_state_consistency_with_labels() -> Result<()> { + let mut ctx = TestContext::new().await?; + + // Assign labels to both accounts + let from_label = Label::new("idx-sender-label"); + let to_label = Label::new("idx-receiver-label"); + + let label_cmd = Command::Account(wallet::cli::account::AccountSubcommand::Label { + account_id: public_mention(ctx.existing_public_accounts()[0]), + label: from_label.clone(), + }); + wallet::cli::execute_subcommand(ctx.wallet_mut(), label_cmd).await?; + + let label_cmd = Command::Account(wallet::cli::account::AccountSubcommand::Label { + account_id: public_mention(ctx.existing_public_accounts()[1]), + label: to_label.clone(), + }); + wallet::cli::execute_subcommand(ctx.wallet_mut(), label_cmd).await?; + + // Send using labels instead of account IDs + let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + from: CliAccountMention::Label(from_label), + to: Some(CliAccountMention::Label(to_label)), + to_npk: None, + to_vpk: None, + to_keys: None, + to_identifier: Some(0), + amount: 100, + }); + + wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?; + + info!("Waiting for next block creation"); + tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + + let acc_1_balance = sequencer_service_rpc::RpcClient::get_account_balance( + ctx.sequencer_client(), + ctx.existing_public_accounts()[0], + ) + .await?; + let acc_2_balance = sequencer_service_rpc::RpcClient::get_account_balance( + ctx.sequencer_client(), + ctx.existing_public_accounts()[1], + ) + .await?; + + assert_eq!(acc_1_balance, 9900); + assert_eq!(acc_2_balance, 20100); + + info!("Waiting for indexer to parse blocks"); + wait_for_indexer_to_catch_up(&ctx).await?; + + let acc1_ind_state = ctx + .indexer_client() + .get_account(ctx.existing_public_accounts()[0].into()) + .await + .unwrap(); + let acc1_seq_state = sequencer_service_rpc::RpcClient::get_account( + ctx.sequencer_client(), + ctx.existing_public_accounts()[0], + ) + .await?; + + assert_eq!(acc1_ind_state, acc1_seq_state.into()); + + info!("Indexer state is consistent after label-based transfer"); + + Ok(()) +} diff --git a/integration_tests/tests/indexer_test_run.rs b/integration_tests/tests/indexer_test_run.rs new file mode 100644 index 00000000..b54cdf82 --- /dev/null +++ b/integration_tests/tests/indexer_test_run.rs @@ -0,0 +1,25 @@ +#![expect( + clippy::tests_outside_test_module, + reason = "We don't care about these in tests" +)] + +use anyhow::Result; +use integration_tests::{TestContext, wait_for_indexer_to_catch_up}; +use log::info; + +#[tokio::test] +async fn indexer_test_run() -> Result<()> { + let ctx = TestContext::new().await?; + + let last_block_indexer = wait_for_indexer_to_catch_up(&ctx).await?; + + let last_block_seq = + sequencer_service_rpc::RpcClient::get_last_block_id(ctx.sequencer_client()).await?; + + info!("Last block on seq now is {last_block_seq}"); + info!("Last block on ind now is {last_block_indexer}"); + + assert!(last_block_indexer > 0); + + Ok(()) +} diff --git a/integration_tests/tests/indexer_test_run_ffi.rs b/integration_tests/tests/indexer_test_run_ffi.rs new file mode 100644 index 00000000..2c7c2103 --- /dev/null +++ b/integration_tests/tests/indexer_test_run_ffi.rs @@ -0,0 +1,37 @@ +#![expect( + clippy::tests_outside_test_module, + clippy::undocumented_unsafe_blocks, + reason = "We don't care about these in tests" +)] + +use anyhow::Result; +use indexer_ffi::Runtime; +use integration_tests::L2_TO_L1_TIMEOUT; +use log::info; + +#[path = "indexer_ffi_helpers/mod.rs"] +mod indexer_ffi_helpers; + +#[test] +fn indexer_test_run_ffi() -> Result<()> { + let (ctx, indexer_ffi, _indexer_dir) = indexer_ffi_helpers::setup()?; + + // RUN OBSERVATION + std::thread::sleep(L2_TO_L1_TIMEOUT); + + // Safety: ctx runtime is valid for the lifetime of the returned Runtime + let runtime = unsafe { Runtime::from_borrowed(ctx.runtime()) }; + let last_block_indexer_ffi_res = unsafe { + indexer_ffi_helpers::query_last_block(&raw const runtime, &raw const indexer_ffi) + }; + + assert!(last_block_indexer_ffi_res.error.is_ok()); + + let last_block_indexer_ffi = unsafe { *last_block_indexer_ffi_res.value }; + + info!("Last block on indexer FFI now is {last_block_indexer_ffi}"); + + assert!(last_block_indexer_ffi > 0); + + Ok(()) +} diff --git a/integration_tests/tests/keys.rs b/integration_tests/tests/keys.rs index 0cc3c187..01af23cd 100644 --- a/integration_tests/tests/keys.rs +++ b/integration_tests/tests/keys.rs @@ -12,8 +12,8 @@ use integration_tests::{ public_mention, verify_commitment_is_in_state, }; use key_protocol::key_management::key_tree::chain_index::ChainIndex; +use lee::{AccountId, program::Program}; use log::info; -use nssa::{AccountId, program::Program}; use sequencer_service_rpc::RpcClient as _; use tokio::test; use wallet::cli::{ @@ -71,7 +71,10 @@ async fn sync_private_account_with_non_zero_chain_index() -> Result<()> { from: private_mention(from), to: None, to_npk: Some(hex::encode(to_account.key_chain.nullifier_public_key.0)), - to_vpk: Some(hex::encode(&to_account.key_chain.viewing_public_key.0)), + to_vpk: Some(hex::encode( + to_account.key_chain.viewing_public_key.to_bytes(), + )), + to_keys: None, to_identifier: Some(to_account.kind.identifier()), amount: 100, }); @@ -147,6 +150,7 @@ async fn restore_keys_from_seed() -> Result<()> { to: Some(private_mention(to_account_id1)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: 100, }); @@ -158,6 +162,7 @@ async fn restore_keys_from_seed() -> Result<()> { to: Some(private_mention(to_account_id2)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: 101, }); @@ -197,6 +202,7 @@ async fn restore_keys_from_seed() -> Result<()> { to: Some(public_mention(to_account_id3)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: 102, }); @@ -208,6 +214,7 @@ async fn restore_keys_from_seed() -> Result<()> { to: Some(public_mention(to_account_id4)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: 103, }); @@ -268,6 +275,7 @@ async fn restore_keys_from_seed() -> Result<()> { to: Some(private_mention(to_account_id2)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: 10, }); @@ -278,6 +286,7 @@ async fn restore_keys_from_seed() -> Result<()> { to: Some(public_mention(to_account_id4)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: 11, }); diff --git a/integration_tests/tests/private_pda.rs b/integration_tests/tests/private_pda.rs index b0e3336e..ea7cafab 100644 --- a/integration_tests/tests/private_pda.rs +++ b/integration_tests/tests/private_pda.rs @@ -7,14 +7,13 @@ use std::{path::PathBuf, time::Duration}; use anyhow::{Context as _, Result}; use authenticated_transfer_core::Instruction as AuthTransferInstruction; -use common::transaction::NSSATransaction; +use common::transaction::LeeTransaction; use integration_tests::{ - NSSA_PROGRAM_FOR_TEST_PDA_SPEND_PROXY, TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, + LEE_PROGRAM_FOR_TEST_PDA_SPEND_PROXY, TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, verify_commitment_is_in_state, }; use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; -use log::info; -use nssa::{ +use lee::{ AccountId, PrivacyPreservingTransaction, ProgramId, privacy_preserving_transaction::{ circuit::{ProgramWithDependencies, execute_and_prove}, @@ -23,12 +22,13 @@ use nssa::{ }, program::Program, }; -use nssa_core::{ +use lee_core::{ InputAccountIdentity, NullifierPublicKey, account::{Account, AccountWithMetadata}, encryption::ViewingPublicKey, program::PdaSeed, }; +use log::info; use sequencer_service_rpc::RpcClient as _; use tokio::test; use wallet::{ @@ -64,9 +64,9 @@ async fn fund_private_pda( let sender_pre = AccountWithMetadata::new(sender_account.clone(), true, sender); let pda_pre = AccountWithMetadata::new(Account::default(), false, pda_account_id); - let eph_holder = EphemeralKeyHolder::new(&npk); - let ssk = eph_holder.calculate_shared_secret_sender(&vpk); - let epk = eph_holder.generate_ephemeral_public_key(); + let eph_holder = EphemeralKeyHolder::new(&vpk); + let ssk = eph_holder.calculate_shared_secret_sender(); + let epk = eph_holder.ephemeral_public_key().clone(); let instruction = Program::serialize_instruction(AuthTransferInstruction::Transfer { amount }) .context("failed to serialize auth_transfer instruction")?; @@ -102,7 +102,7 @@ async fn fund_private_pda( wallet .sequencer_client - .send_transaction(NSSATransaction::PrivacyPreserving(tx)) + .send_transaction(LeeTransaction::PrivacyPreserving(tx)) .await .map_err(|e| anyhow::anyhow!("send transaction failed: {e}"))?; @@ -170,7 +170,7 @@ async fn private_pda_family_members_receive_and_spend() -> Result<()> { let proxy = { let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")) .join("../artifacts/test_program_methods") - .join(NSSA_PROGRAM_FOR_TEST_PDA_SPEND_PROXY); + .join(LEE_PROGRAM_FOR_TEST_PDA_SPEND_PROXY); Program::new(std::fs::read(&path).with_context(|| format!("reading {path:?}"))?) .context("invalid pda_spend_proxy binary")? }; @@ -272,10 +272,10 @@ async fn private_pda_family_members_receive_and_spend() -> Result<()> { // Fresh recipients — hardcoded npks not in any wallet. let recipient_npk_0 = NullifierPublicKey([0xAA; 32]); - let recipient_vpk_0 = ViewingPublicKey::from_scalar(recipient_npk_0.0); + let recipient_vpk_0 = ViewingPublicKey::from_seed(&[0_u8; 32], &[1_u8; 32]); let recipient_npk_1 = NullifierPublicKey([0xBB; 32]); - let recipient_vpk_1 = ViewingPublicKey::from_scalar(recipient_npk_1.0); + let recipient_vpk_1 = ViewingPublicKey::from_seed(&[2_u8; 32], &[3_u8; 32]); let amount_spend_0: u128 = 13; let amount_spend_1: u128 = 37; diff --git a/integration_tests/tests/program_deployment.rs b/integration_tests/tests/program_deployment.rs index 64f5a655..77ac1fb9 100644 --- a/integration_tests/tests/program_deployment.rs +++ b/integration_tests/tests/program_deployment.rs @@ -6,12 +6,12 @@ use std::{path::PathBuf, time::Duration}; use anyhow::Result; -use common::transaction::NSSATransaction; +use common::transaction::LeeTransaction; use integration_tests::{ - NSSA_PROGRAM_FOR_TEST_DATA_CHANGER, TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, + LEE_PROGRAM_FOR_TEST_DATA_CHANGER, TIME_TO_WAIT_FOR_BLOCK_SECONDS, TestContext, }; +use lee::program::Program; use log::info; -use nssa::program::Program; use sequencer_service_rpc::RpcClient as _; use tokio::test; use wallet::cli::{ @@ -26,7 +26,7 @@ async fn deploy_and_execute_program() -> Result<()> { let manifest_dir = env!("CARGO_MANIFEST_DIR"); let binary_filepath: PathBuf = PathBuf::from(manifest_dir) .join("../artifacts/test_program_methods") - .join(NSSA_PROGRAM_FOR_TEST_DATA_CHANGER); + .join(LEE_PROGRAM_FOR_TEST_DATA_CHANGER); let command = Command::DeployProgram { binary_filepath: binary_filepath.clone(), @@ -39,7 +39,7 @@ async fn deploy_and_execute_program() -> Result<()> { // The program is the data changer and takes one account as input. // We pass an uninitialized account and we expect after execution to be owned by the data - // changer program (NSSA account claiming mechanism) with data equal to [0] (due to program + // changer program (LEE account claiming mechanism) with data equal to [0] (due to program // logic) let bytecode = std::fs::read(binary_filepath)?; let data_changer = Program::new(bytecode)?; @@ -61,17 +61,17 @@ async fn deploy_and_execute_program() -> Result<()> { .wallet() .get_account_public_signing_key(account_id) .unwrap(); - let message = nssa::public_transaction::Message::try_new( + let message = lee::public_transaction::Message::try_new( data_changer.id(), vec![account_id], nonces, vec![0], )?; - let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[private_key]); - let transaction = nssa::PublicTransaction::new(message, witness_set); + let witness_set = lee::public_transaction::WitnessSet::for_message(&message, &[private_key]); + let transaction = lee::PublicTransaction::new(message, witness_set); let _response = ctx .sequencer_client() - .send_transaction(NSSATransaction::Public(transaction)) + .send_transaction(LeeTransaction::Public(transaction)) .await?; info!("Waiting for next block creation"); diff --git a/integration_tests/tests/shared_accounts.rs b/integration_tests/tests/shared_accounts.rs index aa1077ff..39bdd36c 100644 --- a/integration_tests/tests/shared_accounts.rs +++ b/integration_tests/tests/shared_accounts.rs @@ -107,8 +107,11 @@ async fn group_invite_join_key_agreement() -> Result<()> { .key_chain() .sealing_secret_key() .context("Sealing key not found")?; - let sealing_pk = - key_protocol::key_management::group_key_holder::SealingPublicKey::from_scalar(sealing_sk); + let sealing_pk = key_protocol::key_management::group_key_holder::SealingPublicKey::from_bytes( + lee_core::encryption::ViewingPublicKey::from_seed(&sealing_sk.d, &sealing_sk.z) + .to_bytes() + .to_vec(), + ); let holder = ctx .wallet() @@ -204,6 +207,7 @@ async fn fund_shared_account_from_public() -> Result<()> { to: Some(private_mention(shared_id)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: None, amount: 100, }); diff --git a/integration_tests/tests/token.rs b/integration_tests/tests/token.rs index 65011976..b0c569e8 100644 --- a/integration_tests/tests/token.rs +++ b/integration_tests/tests/token.rs @@ -12,8 +12,8 @@ use integration_tests::{ verify_commitment_is_in_state, }; use key_protocol::key_management::key_tree::chain_index::ChainIndex; +use lee::program::Program; use log::info; -use nssa::program::Program; use sequencer_service_rpc::RpcClient as _; use token_core::{TokenDefinition, TokenHolding}; use tokio::test; @@ -133,6 +133,7 @@ async fn create_and_transfer_public_token() -> Result<()> { to: Some(public_mention(recipient_account_id)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: transfer_amount, }; @@ -223,6 +224,7 @@ async fn create_and_transfer_public_token() -> Result<()> { holder: Some(public_mention(recipient_account_id)), holder_npk: None, holder_vpk: None, + holder_keys: None, holder_identifier: None, amount: mint_amount, }; @@ -365,6 +367,7 @@ async fn create_and_transfer_token_with_private_supply() -> Result<()> { to: Some(private_mention(recipient_account_id)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: transfer_amount, }; @@ -554,6 +557,7 @@ async fn create_token_with_private_definition() -> Result<()> { holder: Some(public_mention(recipient_account_id_public)), holder_npk: None, holder_vpk: None, + holder_keys: None, holder_identifier: None, amount: mint_amount_public, }; @@ -601,6 +605,7 @@ async fn create_token_with_private_definition() -> Result<()> { holder: Some(private_mention(recipient_account_id_private)), holder_npk: None, holder_vpk: None, + holder_keys: None, holder_identifier: None, amount: mint_amount_private, }; @@ -740,6 +745,7 @@ async fn create_token_with_private_definition_and_supply() -> Result<()> { to: Some(private_mention(recipient_account_id)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: transfer_amount, }; @@ -868,6 +874,7 @@ async fn shielded_token_transfer() -> Result<()> { to: Some(private_mention(recipient_account_id)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: transfer_amount, }; @@ -991,6 +998,7 @@ async fn deshielded_token_transfer() -> Result<()> { to: Some(public_mention(recipient_account_id)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: transfer_amount, }; @@ -1124,7 +1132,8 @@ async fn token_claiming_path_with_private_accounts() -> Result<()> { definition: private_mention(definition_account_id), holder: None, holder_npk: Some(hex::encode(holder_keys.nullifier_public_key.0)), - holder_vpk: Some(hex::encode(&holder_keys.viewing_public_key.0)), + holder_vpk: Some(hex::encode(holder_keys.viewing_public_key.to_bytes())), + holder_keys: None, holder_identifier: Some(holder_identifier), amount: mint_amount, }; @@ -1323,6 +1332,7 @@ async fn transfer_token_using_from_label() -> Result<()> { to: Some(public_mention(recipient_account_id)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: transfer_amount, }; diff --git a/integration_tests/tests/tps.rs b/integration_tests/tests/tps.rs index 0a6a9038..daf52609 100644 --- a/integration_tests/tests/tps.rs +++ b/integration_tests/tests/tps.rs @@ -13,21 +13,21 @@ use std::time::{Duration, Instant}; use anyhow::{Context as _, Result}; use bytesize::ByteSize; -use common::transaction::NSSATransaction; +use common::transaction::LeeTransaction; use integration_tests::{TestContext, config::SequencerPartialConfig}; use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; -use log::info; -use nssa::{ +use lee::{ Account, AccountId, PrivacyPreservingTransaction, PrivateKey, PublicKey, PublicTransaction, privacy_preserving_transaction::{self as pptx, circuit}, program::Program, public_transaction as putx, }; -use nssa_core::{ +use lee_core::{ InputAccountIdentity, MembershipProof, NullifierPublicKey, account::{AccountWithMetadata, Nonce, data::Data}, encryption::ViewingPublicKey, }; +use log::info; use sequencer_core::config::GenesisAction; use sequencer_service_rpc::RpcClient as _; use tokio::test; @@ -90,16 +90,16 @@ impl TpsTestManager { ) .context("Failed to build vault claim message")?; let witness_set = - nssa::public_transaction::WitnessSet::for_message(&message, &[private_key]); + lee::public_transaction::WitnessSet::for_message(&message, &[private_key]); let tx = PublicTransaction::new(message, witness_set); let hash = sequencer_client - .send_transaction(NSSATransaction::Public(tx)) + .send_transaction(LeeTransaction::Public(tx)) .await .context("Failed to submit vault claim")?; tx_hashes.push(hash); } - let deadline = Instant::now() + Duration::from_secs(300); + let deadline = Instant::now() + Duration::from_mins(5); for (i, tx_hash) in tx_hashes.iter().enumerate() { loop { anyhow::ensure!( @@ -140,7 +140,7 @@ impl TpsTestManager { ) .unwrap(); let witness_set = - nssa::public_transaction::WitnessSet::for_message(&message, &[&pair[0].0]); + lee::public_transaction::WitnessSet::for_message(&message, &[&pair[0].0]); PublicTransaction::new(message, witness_set) }) .collect(); @@ -202,7 +202,7 @@ pub async fn tps_test() -> Result<()> { for (i, tx) in txs.into_iter().enumerate() { let tx_hash = ctx .sequencer_client() - .send_transaction(NSSATransaction::Public(tx)) + .send_transaction(LeeTransaction::Public(tx)) .await .unwrap(); info!("Sent tx {i}"); @@ -256,8 +256,7 @@ pub async fn tps_test() -> Result<()> { fn build_privacy_transaction() -> PrivacyPreservingTransaction { let program = Program::authenticated_transfer_program(); let sender_nsk = [1; 32]; - let sender_vsk = [99; 32]; - let sender_vpk = ViewingPublicKey::from_scalar(sender_vsk); + let sender_vpk = ViewingPublicKey::from_seed(&[99_u8; 32], &[100_u8; 32]); let sender_npk = NullifierPublicKey::from(&sender_nsk); let sender_pre = AccountWithMetadata::new( Account { @@ -270,8 +269,7 @@ fn build_privacy_transaction() -> PrivacyPreservingTransaction { AccountId::for_regular_private_account(&sender_npk, 0), ); let recipient_nsk = [2; 32]; - let recipient_vsk = [99; 32]; - let recipient_vpk = ViewingPublicKey::from_scalar(recipient_vsk); + let recipient_vpk = ViewingPublicKey::from_seed(&[101_u8; 32], &[102_u8; 32]); let recipient_npk = NullifierPublicKey::from(&recipient_nsk); let recipient_pre = AccountWithMetadata::new( Account::default(), @@ -279,13 +277,13 @@ fn build_privacy_transaction() -> PrivacyPreservingTransaction { AccountId::for_regular_private_account(&recipient_npk, 0), ); - let eph_holder_from = EphemeralKeyHolder::new(&sender_npk); - let sender_ss = eph_holder_from.calculate_shared_secret_sender(&sender_vpk); - let sender_epk = eph_holder_from.generate_ephemeral_public_key(); + let eph_holder_from = EphemeralKeyHolder::new(&sender_vpk); + let sender_ss = eph_holder_from.calculate_shared_secret_sender(); + let sender_epk = eph_holder_from.ephemeral_public_key().clone(); - let eph_holder_to = EphemeralKeyHolder::new(&recipient_npk); - let recipient_ss = eph_holder_to.calculate_shared_secret_sender(&recipient_vpk); - let recipient_epk = eph_holder_from.generate_ephemeral_public_key(); + let eph_holder_to = EphemeralKeyHolder::new(&recipient_vpk); + let recipient_ss = eph_holder_to.calculate_shared_secret_sender(); + let recipient_epk = eph_holder_to.ephemeral_public_key().clone(); let balance_to_move: u128 = 1; let proof: MembershipProof = ( diff --git a/integration_tests/tests/wallet_ffi.rs b/integration_tests/tests/wallet_ffi.rs index 9be04768..70e6d44d 100644 --- a/integration_tests/tests/wallet_ffi.rs +++ b/integration_tests/tests/wallet_ffi.rs @@ -20,9 +20,9 @@ use std::{ use anyhow::Result; use integration_tests::{BlockingTestContext, TIME_TO_WAIT_FOR_BLOCK_SECONDS}; +use lee::{Account, AccountId, PrivateKey, PublicKey, program::Program}; +use lee_core::program::DEFAULT_PROGRAM_ID; use log::info; -use nssa::{Account, AccountId, PrivateKey, PublicKey, program::Program}; -use nssa_core::program::DEFAULT_PROGRAM_ID; use tempfile::tempdir; use wallet::account::HumanReadableAccount; use wallet_ffi::{ @@ -866,7 +866,7 @@ fn test_wallet_ffi_transfer_shielded() -> Result<()> { let (to, to_keys) = unsafe { let mut out_keys = FfiPrivateAccountKeys::default(); wallet_ffi_create_private_accounts_key(wallet_ffi_handle, &raw mut out_keys).unwrap(); - let account_id = nssa::AccountId::for_regular_private_account(&out_keys.npk(), 0_u128); + let account_id = lee::AccountId::for_regular_private_account(&out_keys.npk(), 0_u128); let to: FfiBytes32 = account_id.into(); (to, out_keys) }; @@ -1003,7 +1003,7 @@ fn test_wallet_ffi_transfer_private() -> Result<()> { let (to, to_keys) = unsafe { let mut out_keys = FfiPrivateAccountKeys::default(); wallet_ffi_create_private_accounts_key(wallet_ffi_handle, &raw mut out_keys).unwrap(); - let account_id = nssa::AccountId::for_regular_private_account(&out_keys.npk(), 0_u128); + let account_id = lee::AccountId::for_regular_private_account(&out_keys.npk(), 0_u128); let to: FfiBytes32 = account_id.into(); (to, out_keys) }; diff --git a/key_protocol/src/key_management/ephemeral_key_holder.rs b/key_protocol/src/key_management/ephemeral_key_holder.rs deleted file mode 100644 index 7a6dc7d0..00000000 --- a/key_protocol/src/key_management/ephemeral_key_holder.rs +++ /dev/null @@ -1,53 +0,0 @@ -use nssa_core::{ - NullifierPublicKey, SharedSecretKey, - encryption::{EphemeralPublicKey, EphemeralSecretKey, ViewingPublicKey}, -}; -use rand::{RngCore as _, rngs::OsRng}; -use sha2::Digest as _; - -#[derive(Debug)] -/// Ephemeral secret key holder. Non-clonable as intended for one-time use. Produces ephemeral -/// public keys. Can produce shared secret for sender. -pub struct EphemeralKeyHolder { - ephemeral_secret_key: EphemeralSecretKey, -} - -impl EphemeralKeyHolder { - #[must_use] - pub fn new(receiver_nullifier_public_key: &NullifierPublicKey) -> Self { - let mut nonce_bytes = [0; 16]; - OsRng.fill_bytes(&mut nonce_bytes); - let mut hasher = sha2::Sha256::new(); - hasher.update(receiver_nullifier_public_key); - hasher.update(nonce_bytes); - - Self { - ephemeral_secret_key: hasher.finalize().into(), - } - } - - #[must_use] - pub fn generate_ephemeral_public_key(&self) -> EphemeralPublicKey { - EphemeralPublicKey::from_scalar(self.ephemeral_secret_key) - } - - #[must_use] - pub fn calculate_shared_secret_sender( - &self, - receiver_viewing_public_key: &ViewingPublicKey, - ) -> SharedSecretKey { - SharedSecretKey::new(self.ephemeral_secret_key, receiver_viewing_public_key) - } -} - -#[must_use] -pub fn produce_one_sided_shared_secret_receiver( - vpk: &ViewingPublicKey, -) -> (SharedSecretKey, EphemeralPublicKey) { - let mut esk = [0; 32]; - OsRng.fill_bytes(&mut esk); - ( - SharedSecretKey::new(esk, vpk), - EphemeralPublicKey::from_scalar(esk), - ) -} diff --git a/key_protocol/src/key_management/key_tree/keys_private.rs b/key_protocol/src/key_management/key_tree/keys_private.rs deleted file mode 100644 index ab4c5c29..00000000 --- a/key_protocol/src/key_management/key_tree/keys_private.rs +++ /dev/null @@ -1,226 +0,0 @@ -use std::collections::BTreeMap; - -use k256::{Scalar, elliptic_curve::PrimeField as _}; -use nssa_core::{NullifierPublicKey, PrivateAccountKind, encryption::ViewingPublicKey}; -use serde::{Deserialize, Serialize}; - -use crate::key_management::{ - KeyChain, - key_tree::traits::KeyTreeNode, - secret_holders::{PrivateKeyHolder, SecretSpendingKey}, -}; - -#[derive(Debug, Serialize, Deserialize, Clone)] -#[cfg_attr(any(test, feature = "test_utils"), derive(PartialEq, Eq))] -pub struct ChildKeysPrivate { - pub value: (KeyChain, BTreeMap), - pub ccc: [u8; 32], - /// Can be [`None`] if root. - pub cci: Option, -} - -impl ChildKeysPrivate { - #[must_use] - pub fn root(seed: [u8; 64]) -> Self { - let hash_value = hmac_sha512::HMAC::mac(seed, b"LEE_master_priv"); - - let ssk = SecretSpendingKey( - *hash_value - .first_chunk::<32>() - .expect("hash_value is 64 bytes, must be safe to get first 32"), - ); - let ccc = *hash_value - .last_chunk::<32>() - .expect("hash_value is 64 bytes, must be safe to get last 32"); - - let nsk = ssk.generate_nullifier_secret_key(None); - let vsk = ssk.generate_viewing_secret_key(None); - - let npk = NullifierPublicKey::from(&nsk); - let vpk = ViewingPublicKey::from_scalar(vsk); - - Self { - value: ( - KeyChain { - secret_spending_key: ssk, - nullifier_public_key: npk, - viewing_public_key: vpk, - private_key_holder: PrivateKeyHolder { - nullifier_secret_key: nsk, - viewing_secret_key: vsk, - }, - }, - BTreeMap::from_iter([(PrivateAccountKind::Regular(0), nssa::Account::default())]), - ), - ccc, - cci: None, - } - } - - #[must_use] - pub fn nth_child(&self, cci: u32) -> Self { - #[expect(clippy::arithmetic_side_effects, reason = "TODO: fix later")] - let parent_pt = - Scalar::from_repr(self.value.0.private_key_holder.nullifier_secret_key.into()) - .expect("Key generated as scalar, must be valid representation") - * Scalar::from_repr(self.value.0.private_key_holder.viewing_secret_key.into()) - .expect("Key generated as scalar, must be valid representation"); - let mut input = vec![]; - - input.extend_from_slice(b"LEE_seed_priv"); - input.extend_from_slice(&parent_pt.to_bytes()); - #[expect(clippy::big_endian_bytes, reason = "BIP-032 uses big endian")] - input.extend_from_slice(&cci.to_be_bytes()); - - let hash_value = hmac_sha512::HMAC::mac(input, self.ccc); - - let ssk = SecretSpendingKey( - *hash_value - .first_chunk::<32>() - .expect("hash_value is 64 bytes, must be safe to get first 32"), - ); - let ccc = *hash_value - .last_chunk::<32>() - .expect("hash_value is 64 bytes, must be safe to get last 32"); - - let nsk = ssk.generate_nullifier_secret_key(Some(cci)); - let vsk = ssk.generate_viewing_secret_key(Some(cci)); - - let npk = NullifierPublicKey::from(&nsk); - let vpk = ViewingPublicKey::from_scalar(vsk); - - Self { - value: ( - KeyChain { - secret_spending_key: ssk, - nullifier_public_key: npk, - viewing_public_key: vpk, - private_key_holder: PrivateKeyHolder { - nullifier_secret_key: nsk, - viewing_secret_key: vsk, - }, - }, - BTreeMap::from_iter([(PrivateAccountKind::Regular(0), nssa::Account::default())]), - ), - ccc, - cci: Some(cci), - } - } -} - -impl KeyTreeNode for ChildKeysPrivate { - fn from_seed(seed: [u8; 64]) -> Self { - Self::root(seed) - } - - fn derive_child(&self, cci: u32) -> Self { - self.nth_child(cci) - } - - fn account_ids(&self) -> impl Iterator { - let npk = self.value.0.nullifier_public_key; - self.value - .1 - .keys() - .map(move |kind| nssa::AccountId::for_private_account(&npk, kind)) - } -} - -#[cfg(test)] -mod tests { - use nssa_core::{NullifierPublicKey, NullifierSecretKey}; - - use super::*; - use crate::key_management::{self, secret_holders::ViewingSecretKey}; - - #[expect(clippy::redundant_type_annotations, reason = "TODO: clippy requires")] - #[test] - fn master_key_generation() { - let seed: [u8; 64] = [ - 252, 56, 204, 83, 232, 123, 209, 188, 187, 167, 39, 213, 71, 39, 58, 65, 125, 134, 255, - 49, 43, 108, 92, 53, 173, 164, 94, 142, 150, 74, 21, 163, 43, 144, 226, 87, 199, 18, - 129, 223, 176, 198, 5, 150, 157, 70, 210, 254, 14, 105, 89, 191, 246, 27, 52, 170, 56, - 114, 39, 38, 118, 197, 205, 225, - ]; - - let keys = ChildKeysPrivate::root(seed); - - let expected_ssk: SecretSpendingKey = key_management::secret_holders::SecretSpendingKey([ - 246, 79, 26, 124, 135, 95, 52, 51, 201, 27, 48, 194, 2, 144, 51, 219, 245, 128, 139, - 222, 42, 195, 105, 33, 115, 97, 186, 0, 97, 14, 218, 191, - ]); - - let expected_ccc = [ - 56, 114, 70, 249, 67, 169, 206, 9, 192, 11, 180, 168, 149, 129, 42, 95, 43, 157, 130, - 111, 13, 5, 195, 75, 20, 255, 162, 85, 40, 251, 8, 168, - ]; - - let expected_nsk: NullifierSecretKey = [ - 154, 102, 103, 5, 34, 235, 227, 13, 22, 182, 226, 11, 7, 67, 110, 162, 99, 193, 174, - 34, 234, 19, 222, 2, 22, 12, 163, 252, 88, 11, 0, 163, - ]; - - let expected_npk: NullifierPublicKey = nssa_core::NullifierPublicKey([ - 7, 123, 125, 191, 233, 183, 201, 4, 20, 214, 155, 210, 45, 234, 27, 240, 194, 111, 97, - 247, 155, 113, 122, 246, 192, 0, 70, 61, 76, 71, 70, 2, - ]); - let expected_vsk = [ - 155, 90, 54, 75, 228, 130, 68, 201, 129, 251, 180, 195, 250, 64, 34, 230, 241, 204, - 216, 50, 149, 156, 10, 67, 208, 74, 9, 10, 47, 59, 50, 202, - ]; - - let expected_vpk_as_bytes: [u8; 33] = [ - 2, 191, 99, 102, 114, 40, 131, 109, 166, 8, 222, 186, 107, 29, 156, 106, 206, 96, 127, - 80, 170, 66, 217, 79, 38, 80, 11, 74, 147, 123, 221, 159, 166, - ]; - - assert!(expected_ssk == keys.value.0.secret_spending_key); - assert!(expected_ccc == keys.ccc); - assert!(expected_nsk == keys.value.0.private_key_holder.nullifier_secret_key); - assert!(expected_npk == keys.value.0.nullifier_public_key); - assert!(expected_vsk == keys.value.0.private_key_holder.viewing_secret_key); - assert!(expected_vpk_as_bytes == keys.value.0.viewing_public_key.to_bytes()); - } - - #[test] - fn child_keys_generation() { - let seed: [u8; 64] = [ - 252, 56, 204, 83, 232, 123, 209, 188, 187, 167, 39, 213, 71, 39, 58, 65, 125, 134, 255, - 49, 43, 108, 92, 53, 173, 164, 94, 142, 150, 74, 21, 163, 43, 144, 226, 87, 199, 18, - 129, 223, 176, 198, 5, 150, 157, 70, 210, 254, 14, 105, 89, 191, 246, 27, 52, 170, 56, - 114, 39, 38, 118, 197, 205, 225, - ]; - - let root_node = ChildKeysPrivate::root(seed); - let child_node = ChildKeysPrivate::nth_child(&root_node, 42_u32); - - let expected_ccc: [u8; 32] = [ - 27, 73, 133, 213, 214, 63, 217, 184, 164, 17, 172, 140, 223, 95, 255, 157, 11, 0, 58, - 53, 82, 147, 121, 120, 199, 50, 30, 28, 103, 24, 121, 187, - ]; - - let expected_nsk: NullifierSecretKey = [ - 124, 61, 40, 92, 33, 135, 3, 41, 200, 234, 3, 69, 102, 184, 57, 191, 106, 151, 194, - 192, 103, 132, 141, 112, 249, 108, 192, 117, 24, 48, 70, 216, - ]; - let expected_npk = nssa_core::NullifierPublicKey([ - 116, 231, 246, 189, 145, 240, 37, 59, 219, 223, 216, 246, 116, 171, 223, 55, 197, 200, - 134, 192, 221, 40, 218, 167, 239, 5, 11, 95, 147, 247, 162, 226, - ]); - - let expected_vsk: ViewingSecretKey = [ - 33, 155, 68, 60, 102, 70, 47, 105, 194, 129, 44, 26, 143, 198, 44, 244, 185, 31, 236, - 252, 205, 89, 138, 107, 39, 38, 154, 73, 109, 166, 41, 114, - ]; - let expected_vpk_as_bytes: [u8; 33] = [ - 2, 78, 213, 113, 117, 105, 162, 248, 175, 68, 128, 232, 106, 204, 208, 159, 11, 78, 48, - 244, 127, 112, 46, 0, 93, 184, 1, 77, 132, 160, 75, 152, 88, - ]; - - assert!(expected_ccc == child_node.ccc); - assert!(expected_nsk == child_node.value.0.private_key_holder.nullifier_secret_key); - assert!(expected_npk == child_node.value.0.nullifier_public_key); - assert!(expected_vsk == child_node.value.0.private_key_holder.viewing_secret_key); - assert!(expected_vpk_as_bytes == child_node.value.0.viewing_public_key.to_bytes()); - } -} diff --git a/key_protocol/Cargo.toml b/lee/key_protocol/Cargo.toml similarity index 88% rename from key_protocol/Cargo.toml rename to lee/key_protocol/Cargo.toml index a0b5c397..06c244c7 100644 --- a/key_protocol/Cargo.toml +++ b/lee/key_protocol/Cargo.toml @@ -12,13 +12,14 @@ default = [] test_utils = [] [dependencies] -nssa.workspace = true -nssa_core.workspace = true +lee.workspace = true +lee_core.workspace = true common.workspace = true anyhow.workspace = true serde.workspace = true k256.workspace = true +ml-kem.workspace = true sha2.workspace = true rand.workspace = true hex.workspace = true diff --git a/lee/key_protocol/src/key_management/ephemeral_key_holder.rs b/lee/key_protocol/src/key_management/ephemeral_key_holder.rs new file mode 100644 index 00000000..a53ae47c --- /dev/null +++ b/lee/key_protocol/src/key_management/ephemeral_key_holder.rs @@ -0,0 +1,61 @@ +use lee_core::{ + SharedSecretKey, + encryption::{EphemeralPublicKey, ViewingPublicKey}, +}; + +/// Ephemeral key holder for the sender side of a KEM-based shared-secret exchange. +/// +/// Non-clonable as intended for one-time use: construction encapsulates once and +/// stores both the shared secret and the ciphertext (`EphemeralPublicKey`) that must +/// be sent to the receiver. +pub struct EphemeralKeyHolder { + shared_secret: SharedSecretKey, + ephemeral_public_key: EphemeralPublicKey, +} + +// SharedSecretKey does not implement Debug (intentional — leaking key material via +// debug output would be a security risk). We implement Debug manually here, redacting the +// shared secret while still allowing the ephemeral public key (KEM ciphertext) to be inspected. +impl std::fmt::Debug for EphemeralKeyHolder { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("EphemeralKeyHolder") + .field("shared_secret", &"") + .field("ephemeral_public_key", &self.ephemeral_public_key) + .finish() + } +} + +impl EphemeralKeyHolder { + #[must_use] + pub fn new(receiver_viewing_public_key: &ViewingPublicKey) -> Self { + let (shared_secret, ephemeral_public_key) = + SharedSecretKey::encapsulate(receiver_viewing_public_key); + Self { + shared_secret, + ephemeral_public_key, + } + } + + /// Returns the KEM ciphertext to be transmitted to the receiver as the `EphemeralPublicKey`. + #[must_use] + pub const fn ephemeral_public_key(&self) -> &EphemeralPublicKey { + &self.ephemeral_public_key + } + + /// Returns the sender-side shared secret (established at construction time). + #[must_use] + pub const fn calculate_shared_secret_sender(&self) -> SharedSecretKey { + self.shared_secret + } +} + +/// Encapsulates a fresh shared secret toward `vpk` and returns `(shared_secret, ciphertext)`. +/// +/// Used when the local side is acting as an "ephemeral receiver" — i.e. generating a +/// one-sided encryption that only the holder of the VSK can decrypt. +#[must_use] +pub fn produce_one_sided_shared_secret_receiver( + vpk: &ViewingPublicKey, +) -> (SharedSecretKey, EphemeralPublicKey) { + SharedSecretKey::encapsulate(vpk) +} diff --git a/key_protocol/src/key_management/group_key_holder.rs b/lee/key_protocol/src/key_management/group_key_holder.rs similarity index 85% rename from key_protocol/src/key_management/group_key_holder.rs rename to lee/key_protocol/src/key_management/group_key_holder.rs index 39a3fd19..7fb24713 100644 --- a/key_protocol/src/key_management/group_key_holder.rs +++ b/lee/key_protocol/src/key_management/group_key_holder.rs @@ -1,44 +1,39 @@ use aes_gcm::{Aes256Gcm, KeyInit as _, aead::Aead as _}; -use nssa_core::{ +use lee_core::{ SharedSecretKey, - encryption::{Scalar, shared_key_derivation::Secp256k1Point}, + encryption::{EphemeralPublicKey, ViewingPublicKey}, program::{PdaSeed, ProgramId}, }; use rand::{RngCore as _, rngs::OsRng}; use serde::{Deserialize, Serialize}; use sha2::{Digest as _, digest::FixedOutput as _}; -use super::secret_holders::{PrivateKeyHolder, SecretSpendingKey}; +use super::secret_holders::{PrivateKeyHolder, SecretSpendingKey, ViewingSecretKey}; /// Public key used to seal a `GroupKeyHolder` for distribution to a recipient. /// -/// Wraps a secp256k1 point but is a distinct type from `ViewingPublicKey` to enforce -/// key separation: viewing keys encrypt account state, sealing keys encrypt the GMS -/// for off-chain distribution. -pub struct SealingPublicKey(Secp256k1Point); +/// Wraps the ML-KEM-768 encapsulation key bytes (1184 bytes). Distinct from +/// `ViewingPublicKey` to enforce key separation: viewing keys encrypt account state, +/// sealing keys encrypt the GMS for off-chain distribution. +pub struct SealingPublicKey(Vec); impl SealingPublicKey { - /// Derive the sealing public key from a secret scalar. - #[must_use] - pub fn from_scalar(scalar: Scalar) -> Self { - Self(Secp256k1Point::from_scalar(scalar)) - } - - /// Construct from raw serialized bytes (e.g. received from another wallet). + /// Construct from raw serialized encapsulation-key bytes (e.g. received from another wallet). #[must_use] pub const fn from_bytes(bytes: Vec) -> Self { - Self(Secp256k1Point(bytes)) + Self(bytes) } /// Returns the raw bytes for display or transmission. #[must_use] pub fn to_bytes(&self) -> &[u8] { - &self.0.0 + &self.0 } } /// Secret key used to unseal a `GroupKeyHolder` received from another member. -pub type SealingSecretKey = Scalar; +/// Holds the two 32-byte FIPS 203 seed halves `d` and `z`. +pub type SealingSecretKey = ViewingSecretKey; /// Manages shared viewing keys for a group of controllers owning private PDAs. /// @@ -153,18 +148,17 @@ impl GroupKeyHolder { /// Encrypts this holder's GMS under the recipient's [`SealingPublicKey`]. /// - /// Uses an ephemeral ECDH key exchange to derive a shared secret, then AES-256-GCM - /// to encrypt the payload. The returned bytes are - /// `ephemeral_pubkey (33) || nonce (12) || ciphertext+tag (48)` = 93 bytes. + /// Uses ML-KEM-768 encapsulation to derive a shared secret, then AES-256-GCM to encrypt + /// the payload. The returned bytes are + /// `kem_ciphertext (1088) || nonce (12) || ciphertext+tag (48)` = 1148 bytes. /// - /// Each call generates a fresh ephemeral key, so two seals of the same holder produce + /// Each call generates a fresh KEM encapsulation, so two seals of the same holder produce /// different ciphertexts. #[must_use] pub fn seal_for(&self, recipient_key: &SealingPublicKey) -> Vec { - let mut ephemeral_scalar: Scalar = [0_u8; 32]; - OsRng.fill_bytes(&mut ephemeral_scalar); - let ephemeral_pubkey = Secp256k1Point::from_scalar(ephemeral_scalar); - let shared = SharedSecretKey::new(ephemeral_scalar, &recipient_key.0); + let sealing_key = ViewingPublicKey::from_bytes(recipient_key.0.clone()) + .expect("key_protocol::group_key_holder::GroupKeyHolder::seal_for: SealingPublicKey must be a valid ML-KEM-768 encapsulation key"); + let (shared, kem_ct) = SharedSecretKey::encapsulate(&sealing_key); let aes_key = Self::seal_kdf(&shared); let cipher = Aes256Gcm::new(&aes_key.into()); @@ -176,12 +170,12 @@ impl GroupKeyHolder { .encrypt(&nonce, self.gms.as_ref()) .expect("AES-GCM encryption should not fail with valid key/nonce"); - let capacity = 33_usize + let capacity = 1088_usize .checked_add(12) .and_then(|n| n.checked_add(ciphertext.len())) .expect("seal capacity overflow"); let mut out = Vec::with_capacity(capacity); - out.extend_from_slice(&ephemeral_pubkey.0); + out.extend_from_slice(&kem_ct.0); out.extend_from_slice(&nonce_bytes); out.extend_from_slice(&ciphertext); out @@ -189,20 +183,24 @@ impl GroupKeyHolder { /// Decrypts a sealed `GroupKeyHolder` using the recipient's [`SealingSecretKey`]. /// - /// Returns `Err` if the ciphertext is too short, the ECDH point is invalid, or the - /// AES-GCM authentication tag doesn't verify (wrong key or tampered data). - pub fn unseal(sealed: &[u8], own_key: SealingSecretKey) -> Result { - const HEADER_LEN: usize = 33 + 12; + /// Returns `Err` if the ciphertext is too short or the AES-GCM authentication tag + /// doesn't verify (wrong key or tampered data). + pub fn unseal(sealed: &[u8], own_key: &SealingSecretKey) -> Result { + // kem_ciphertext (1088) + nonce (12) = header, then AES-GCM tag (16) minimum. + const KEM_CT_LEN: usize = 1088; + const HEADER_LEN: usize = KEM_CT_LEN + 12; const MIN_LEN: usize = HEADER_LEN + 16; + if sealed.len() < MIN_LEN { return Err(SealError::TooShort); } - // MIN_LEN (61) > HEADER_LEN (45), so all slicing below is in bounds. - let ephemeral_pubkey = Secp256k1Point(sealed[..33].to_vec()); - let nonce = aes_gcm::Nonce::from_slice(&sealed[33..HEADER_LEN]); + + let kem_ct = EphemeralPublicKey(sealed[..KEM_CT_LEN].to_vec()); + let nonce = aes_gcm::Nonce::from_slice(&sealed[KEM_CT_LEN..HEADER_LEN]); let ciphertext = &sealed[HEADER_LEN..]; - let shared = SharedSecretKey::new(own_key, &ephemeral_pubkey); + let shared = SharedSecretKey::decapsulate(&kem_ct, &own_key.d, &own_key.z) + .expect("key_protocol::group_key_holder::GroupKeyHolder::unseal: KEM_CT_LEN guarantees exactly 1088 bytes"); let aes_key = Self::seal_kdf(&shared); let cipher = Aes256Gcm::new(&aes_key.into()); @@ -219,7 +217,7 @@ impl GroupKeyHolder { Ok(Self::from_gms(gms)) } - /// Derives an AES-256 key from the ECDH shared secret via SHA-256 with a domain prefix. + /// Derives an AES-256 key from the ML-KEM shared secret via SHA-256 with a domain prefix. fn seal_kdf(shared: &SharedSecretKey) -> [u8; 32] { const PREFIX: &[u8; 32] = b"/LEE/v0.3/GroupKeySeal/AES\x00\x00\x00\x00\x00\x00"; let mut hasher = sha2::Sha256::new(); @@ -237,7 +235,7 @@ pub enum SealError { #[cfg(test)] mod tests { - use nssa_core::NullifierPublicKey; + use lee_core::NullifierPublicKey; use super::*; @@ -326,10 +324,10 @@ mod tests { /// Pins the end-to-end derivation for a fixed (GMS, `ProgramId`, `PdaSeed`). Any change /// to `secret_spending_key_for_pda`, the `PrivateKeyHolder` nsk/npk chain, or the /// `AccountId::for_private_pda` formula breaks this test. Mirrors the pinned-value - /// pattern from `for_private_pda_matches_pinned_value` in `nssa_core`. + /// pattern from `for_private_pda_matches_pinned_value` in `lee_core`. #[test] fn pinned_end_to_end_derivation_for_private_pda() { - use nssa_core::{account::AccountId, program::ProgramId}; + use lee_core::{account::AccountId, program::ProgramId}; let gms = [42_u8; 32]; let seed = PdaSeed::new([1; 32]); @@ -407,8 +405,10 @@ mod tests { let recipient_vpk = recipient_keys.generate_viewing_public_key(); let recipient_vsk = recipient_keys.viewing_secret_key; - let sealed = holder.seal_for(&SealingPublicKey::from_bytes(recipient_vpk.0)); - let restored = GroupKeyHolder::unseal(&sealed, recipient_vsk).expect("unseal"); + let sealed = holder.seal_for(&SealingPublicKey::from_bytes( + recipient_vpk.to_bytes().to_vec(), + )); + let restored = GroupKeyHolder::unseal(&sealed, &recipient_vsk).expect("unseal"); assert_eq!(restored.dangerous_raw_gms(), holder.dangerous_raw_gms()); @@ -433,13 +433,14 @@ mod tests { .produce_private_key_holder(None) .generate_viewing_public_key(); - let wrong_ssk = SecretSpendingKey([99_u8; 32]); - let wrong_vsk = wrong_ssk + let wrong_vsk = SecretSpendingKey([99_u8; 32]) .produce_private_key_holder(None) .viewing_secret_key; - let sealed = holder.seal_for(&SealingPublicKey::from_bytes(recipient_vpk.0)); - let result = GroupKeyHolder::unseal(&sealed, wrong_vsk); + let sealed = holder.seal_for(&SealingPublicKey::from_bytes( + recipient_vpk.to_bytes().to_vec(), + )); + let result = GroupKeyHolder::unseal(&sealed, &wrong_vsk); assert!(matches!(result, Err(super::SealError::DecryptionFailed))); } @@ -453,16 +454,18 @@ mod tests { let recipient_vpk = recipient_keys.generate_viewing_public_key(); let recipient_vsk = recipient_keys.viewing_secret_key; - let mut sealed = holder.seal_for(&SealingPublicKey::from_bytes(recipient_vpk.0)); - // Flip a byte in the ciphertext portion (after ephemeral_pubkey + nonce) + let mut sealed = holder.seal_for(&SealingPublicKey::from_bytes( + recipient_vpk.to_bytes().to_vec(), + )); + // Flip a byte in the AES-GCM ciphertext portion (after KEM ciphertext + nonce). let last = sealed.len() - 1; sealed[last] ^= 0xFF; - let result = GroupKeyHolder::unseal(&sealed, recipient_vsk); + let result = GroupKeyHolder::unseal(&sealed, &recipient_vsk); assert!(matches!(result, Err(super::SealError::DecryptionFailed))); } - /// Two seals of the same holder produce different ciphertexts (ephemeral randomness). + /// Two seals of the same holder produce different ciphertexts (KEM randomness). #[test] fn two_seals_produce_different_ciphertexts() { let holder = GroupKeyHolder::from_gms([42_u8; 32]); @@ -472,7 +475,7 @@ mod tests { .produce_private_key_holder(None) .generate_viewing_public_key(); - let sealing_key = SealingPublicKey::from_bytes(recipient_vpk.0); + let sealing_key = SealingPublicKey::from_bytes(recipient_vpk.to_bytes().to_vec()); let sealed_a = holder.seal_for(&sealing_key); let sealed_b = holder.seal_for(&sealing_key); assert_ne!(sealed_a, sealed_b); @@ -481,14 +484,15 @@ mod tests { /// Sealed payload is too short. #[test] fn unseal_too_short_fails() { - let vsk: SealingSecretKey = [7_u8; 32]; - let result = GroupKeyHolder::unseal(&[0_u8; 10], vsk); + let vsk = SealingSecretKey { + d: [7_u8; 32], + z: [0_u8; 32], + }; + let result = GroupKeyHolder::unseal(&[0_u8; 10], &vsk); assert!(matches!(result, Err(super::SealError::TooShort))); } - /// Degenerate GMS values (all-zeros, all-ones, single-bit) must still produce valid, - /// non-zero, pairwise-distinct npks. Rules out accidental "if gms == default { return - /// default }" style shortcuts in the derivation. + /// Degenerate GMS values must still produce valid, non-zero, pairwise-distinct npks. #[test] fn degenerate_gms_produces_distinct_non_zero_keys() { let seed = PdaSeed::new([1; 32]); @@ -520,27 +524,25 @@ mod tests { /// Full lifecycle: create group, distribute GMS via seal/unseal, verify key agreement. #[test] fn group_pda_lifecycle() { - use nssa_core::account::AccountId; + use lee_core::account::AccountId; let alice_holder = GroupKeyHolder::new(); let pda_seed = PdaSeed::new([42_u8; 32]); - let program_id: nssa_core::program::ProgramId = [1; 8]; + let program_id: lee_core::program::ProgramId = [1; 8]; - // Derive Alice's keys let alice_keys = alice_holder.derive_keys_for_pda(&TEST_PROGRAM_ID, &pda_seed); let alice_npk = alice_keys.generate_nullifier_public_key(); - // Seal GMS for Bob using Bob's viewing key, Bob unseals let bob_ssk = SecretSpendingKey([77_u8; 32]); let bob_keys = bob_ssk.produce_private_key_holder(None); let bob_vpk = bob_keys.generate_viewing_public_key(); let bob_vsk = bob_keys.viewing_secret_key; - let sealed = alice_holder.seal_for(&SealingPublicKey::from_bytes(bob_vpk.0)); + let sealed = + alice_holder.seal_for(&SealingPublicKey::from_bytes(bob_vpk.to_bytes().to_vec())); let bob_holder = - GroupKeyHolder::unseal(&sealed, bob_vsk).expect("Bob should unseal the GMS"); + GroupKeyHolder::unseal(&sealed, &bob_vsk).expect("Bob should unseal the GMS"); - // Key agreement: both derive identical NPK and AccountId let bob_npk = bob_holder .derive_keys_for_pda(&TEST_PROGRAM_ID, &pda_seed) .generate_nullifier_public_key(); diff --git a/key_protocol/src/key_management/key_tree/chain_index.rs b/lee/key_protocol/src/key_management/key_tree/chain_index.rs similarity index 100% rename from key_protocol/src/key_management/key_tree/chain_index.rs rename to lee/key_protocol/src/key_management/key_tree/chain_index.rs diff --git a/lee/key_protocol/src/key_management/key_tree/keys_private.rs b/lee/key_protocol/src/key_management/key_tree/keys_private.rs new file mode 100644 index 00000000..5a27be79 --- /dev/null +++ b/lee/key_protocol/src/key_management/key_tree/keys_private.rs @@ -0,0 +1,369 @@ +use std::collections::BTreeMap; + +use lee_core::{NullifierPublicKey, PrivateAccountKind, encryption::ViewingPublicKey}; +use serde::{Deserialize, Serialize}; +use sha2::Digest as _; + +use crate::key_management::{ + KeyChain, + key_tree::traits::KeyTreeNode, + secret_holders::{PrivateKeyHolder, SecretSpendingKey}, +}; + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[cfg_attr(any(test, feature = "test_utils"), derive(PartialEq, Eq))] +pub struct ChildKeysPrivate { + pub value: (KeyChain, BTreeMap), + pub ccc: [u8; 32], + /// Can be [`None`] if root. + pub cci: Option, +} + +impl ChildKeysPrivate { + #[must_use] + pub fn root(seed: [u8; 64]) -> Self { + let hash_value = hmac_sha512::HMAC::mac(seed, b"LEE_master_priv"); + + let ssk = SecretSpendingKey( + *hash_value + .first_chunk::<32>() + .expect("hash_value is 64 bytes, must be safe to get first 32"), + ); + let ccc = *hash_value + .last_chunk::<32>() + .expect("hash_value is 64 bytes, must be safe to get last 32"); + + let nsk = ssk.generate_nullifier_secret_key(None); + let vsk = ssk.generate_viewing_secret_seed_key(None); + + let npk = NullifierPublicKey::from(&nsk); + let vpk = ViewingPublicKey::from(&vsk); + + Self { + value: ( + KeyChain { + secret_spending_key: ssk, + nullifier_public_key: npk, + viewing_public_key: vpk, + private_key_holder: PrivateKeyHolder { + nullifier_secret_key: nsk, + viewing_secret_key: vsk, + }, + }, + BTreeMap::from_iter([(PrivateAccountKind::Regular(0), lee::Account::default())]), + ), + ccc, + cci: None, + } + } + + #[must_use] + pub fn nth_child(&self, cci: u32) -> Self { + // `parent_hash`` is used to incorporate entropy based on the parent node's keys + // to generate the `ssk` and `ccc` values. + let mut parent_hash = sha2::Sha256::new(); + parent_hash.update(b"LEE/keys"); + parent_hash.update(self.value.0.private_key_holder.nullifier_secret_key); + parent_hash.update(self.value.0.private_key_holder.viewing_secret_key.d); + parent_hash.update(self.value.0.private_key_holder.viewing_secret_key.z); + let parent_pt = parent_hash.finalize(); + + // Each child (of the same parent node) share the same `parent_pt`. + // To ensure that each child generates unique keys, we include the child index. + let mut input = vec![]; + input.extend_from_slice(b"LEE_seed_priv"); + input.extend_from_slice(&parent_pt); + #[expect(clippy::big_endian_bytes, reason = "BIP-032 uses big endian")] + input.extend_from_slice(&cci.to_be_bytes()); + + let hash_value = hmac_sha512::HMAC::mac(input, self.ccc); + + let ssk = SecretSpendingKey( + *hash_value + .first_chunk::<32>() + .expect("hash_value is 64 bytes, must be safe to get first 32"), + ); + let ccc = *hash_value + .last_chunk::<32>() + .expect("hash_value is 64 bytes, must be safe to get last 32"); + + let nsk = ssk.generate_nullifier_secret_key(Some(cci)); + let vsk = ssk.generate_viewing_secret_seed_key(Some(cci)); + + let npk = NullifierPublicKey::from(&nsk); + let vpk = ViewingPublicKey::from(&vsk); + + Self { + value: ( + KeyChain { + secret_spending_key: ssk, + nullifier_public_key: npk, + viewing_public_key: vpk, + private_key_holder: PrivateKeyHolder { + nullifier_secret_key: nsk, + viewing_secret_key: vsk, + }, + }, + BTreeMap::from_iter([(PrivateAccountKind::Regular(0), lee::Account::default())]), + ), + ccc, + cci: Some(cci), + } + } +} + +impl KeyTreeNode for ChildKeysPrivate { + fn from_seed(seed: [u8; 64]) -> Self { + Self::root(seed) + } + + fn derive_child(&self, cci: u32) -> Self { + self.nth_child(cci) + } + + fn account_ids(&self) -> impl Iterator { + let npk = self.value.0.nullifier_public_key; + self.value + .1 + .keys() + .map(move |kind| lee::AccountId::for_private_account(&npk, kind)) + } +} + +#[cfg(test)] +mod tests { + use lee_core::NullifierSecretKey; + + use super::*; + use crate::key_management::{self, secret_holders::ViewingSecretKey}; + + #[test] + fn master_key_generation() { + let seed: [u8; 64] = [ + 252, 56, 204, 83, 232, 123, 209, 188, 187, 167, 39, 213, 71, 39, 58, 65, 125, 134, 255, + 49, 43, 108, 92, 53, 173, 164, 94, 142, 150, 74, 21, 163, 43, 144, 226, 87, 199, 18, + 129, 223, 176, 198, 5, 150, 157, 70, 210, 254, 14, 105, 89, 191, 246, 27, 52, 170, 56, + 114, 39, 38, 118, 197, 205, 225, + ]; + + let keys = ChildKeysPrivate::root(seed); + + let expected_ssk = key_management::secret_holders::SecretSpendingKey([ + 246, 79, 26, 124, 135, 95, 52, 51, 201, 27, 48, 194, 2, 144, 51, 219, 245, 128, 139, + 222, 42, 195, 105, 33, 115, 97, 186, 0, 97, 14, 218, 191, + ]); + + let expected_ccc = [ + 56, 114, 70, 249, 67, 169, 206, 9, 192, 11, 180, 168, 149, 129, 42, 95, 43, 157, 130, + 111, 13, 5, 195, 75, 20, 255, 162, 85, 40, 251, 8, 168, + ]; + + let expected_nsk: NullifierSecretKey = [ + 154, 102, 103, 5, 34, 235, 227, 13, 22, 182, 226, 11, 7, 67, 110, 162, 99, 193, 174, + 34, 234, 19, 222, 2, 22, 12, 163, 252, 88, 11, 0, 163, + ]; + + let expected_npk = lee_core::NullifierPublicKey([ + 7, 123, 125, 191, 233, 183, 201, 4, 20, 214, 155, 210, 45, 234, 27, 240, 194, 111, 97, + 247, 155, 113, 122, 246, 192, 0, 70, 61, 76, 71, 70, 2, + ]); + + let expected_vsk = ViewingSecretKey::new( + [ + 187, 143, 146, 12, 68, 148, 25, 203, 21, 92, 131, 2, 221, 81, 117, 62, 98, 194, + 159, 177, 102, 254, 236, 182, 76, 242, 116, 219, 17, 166, 99, 36, + ], + [ + 80, 97, 83, 209, 145, 99, 168, 99, 89, 29, 153, 236, 82, 99, 134, 114, 168, 19, + 223, 69, 34, 47, 76, 76, 15, 97, 245, 184, 25, 103, 251, 82, + ], + ); + + let expected_vpk: [u8; 1184] = [ + 127, 229, 162, 212, 104, 117, 4, 150, 192, 103, 122, 195, 14, 35, 12, 60, 52, 23, 220, + 150, 100, 203, 34, 34, 127, 232, 156, 43, 218, 109, 6, 160, 67, 35, 210, 194, 25, 181, + 118, 237, 25, 129, 51, 160, 189, 51, 99, 184, 57, 28, 121, 240, 236, 2, 170, 198, 26, + 91, 172, 110, 52, 32, 186, 35, 179, 202, 234, 249, 15, 242, 100, 198, 168, 163, 120, + 205, 118, 85, 195, 210, 187, 95, 150, 154, 8, 68, 165, 237, 87, 166, 101, 57, 4, 18, + 11, 122, 235, 180, 199, 154, 165, 158, 55, 136, 30, 237, 43, 167, 215, 68, 80, 102, 0, + 71, 90, 130, 206, 240, 215, 69, 199, 83, 7, 60, 184, 128, 230, 184, 61, 93, 201, 204, + 165, 104, 9, 127, 220, 52, 246, 217, 131, 251, 2, 170, 133, 6, 51, 40, 224, 101, 61, + 16, 135, 32, 182, 201, 68, 58, 171, 54, 161, 184, 243, 38, 106, 200, 251, 17, 172, 8, + 24, 73, 230, 55, 85, 20, 147, 222, 165, 200, 116, 135, 47, 20, 227, 56, 220, 64, 120, + 215, 245, 58, 86, 102, 149, 252, 193, 163, 160, 59, 82, 138, 249, 171, 1, 54, 199, 193, + 171, 85, 38, 64, 56, 121, 106, 84, 57, 252, 94, 147, 16, 191, 196, 104, 47, 129, 84, + 21, 252, 160, 81, 207, 184, 199, 3, 177, 74, 117, 115, 175, 138, 108, 36, 198, 5, 32, + 15, 218, 3, 20, 19, 15, 251, 209, 86, 128, 139, 148, 78, 10, 34, 144, 149, 74, 102, 48, + 59, 70, 124, 47, 193, 100, 26, 9, 104, 178, 102, 156, 199, 242, 101, 147, 161, 87, 27, + 234, 192, 204, 41, 36, 43, 83, 219, 15, 211, 66, 91, 76, 73, 13, 113, 155, 203, 193, + 160, 130, 84, 103, 47, 70, 100, 147, 169, 65, 119, 84, 121, 122, 161, 76, 203, 144, + 248, 145, 22, 8, 46, 121, 44, 77, 20, 149, 66, 179, 56, 149, 231, 98, 184, 9, 64, 14, + 67, 196, 34, 8, 123, 21, 80, 169, 168, 223, 230, 133, 0, 66, 159, 230, 69, 201, 205, + 169, 105, 196, 21, 71, 84, 70, 58, 165, 165, 134, 186, 232, 60, 70, 51, 57, 239, 74, + 174, 116, 234, 36, 178, 49, 42, 168, 250, 104, 141, 106, 0, 109, 52, 86, 104, 243, 62, + 214, 137, 48, 107, 2, 152, 206, 227, 175, 147, 236, 19, 113, 27, 191, 231, 235, 167, + 114, 104, 23, 126, 203, 94, 242, 149, 171, 115, 170, 89, 244, 58, 29, 176, 73, 203, 44, + 8, 32, 9, 226, 32, 78, 246, 38, 235, 149, 133, 25, 243, 47, 124, 180, 200, 211, 165, + 137, 56, 169, 117, 31, 244, 65, 91, 135, 146, 158, 20, 75, 102, 32, 65, 250, 103, 199, + 36, 48, 31, 155, 164, 191, 222, 85, 37, 66, 243, 17, 120, 104, 0, 228, 83, 200, 116, 6, + 199, 106, 236, 139, 246, 216, 152, 241, 211, 85, 106, 200, 44, 231, 240, 66, 3, 193, + 147, 16, 145, 65, 49, 33, 53, 247, 69, 47, 44, 113, 86, 117, 6, 20, 193, 183, 128, 178, + 181, 21, 251, 99, 39, 149, 210, 146, 106, 181, 186, 7, 36, 63, 186, 234, 191, 164, 193, + 162, 127, 250, 122, 189, 219, 21, 92, 48, 86, 209, 184, 99, 160, 201, 162, 145, 20, + 138, 154, 18, 37, 180, 209, 165, 165, 51, 187, 78, 193, 175, 135, 6, 55, 216, 178, 10, + 40, 246, 98, 128, 80, 14, 38, 69, 113, 123, 54, 94, 43, 50, 106, 167, 17, 77, 163, 148, + 117, 225, 9, 7, 253, 240, 157, 96, 103, 33, 100, 37, 37, 20, 53, 138, 234, 55, 45, 232, + 154, 9, 150, 192, 116, 36, 119, 106, 95, 119, 34, 220, 84, 174, 19, 227, 33, 209, 96, + 197, 148, 230, 197, 59, 117, 130, 7, 116, 11, 0, 197, 16, 249, 151, 31, 4, 64, 29, 165, + 247, 110, 176, 166, 4, 112, 136, 101, 208, 7, 179, 38, 183, 134, 58, 107, 207, 160, 38, + 159, 67, 112, 20, 225, 199, 179, 133, 117, 144, 54, 199, 15, 204, 80, 154, 116, 84, 88, + 109, 113, 5, 207, 226, 21, 62, 247, 122, 14, 156, 9, 8, 76, 26, 148, 67, 196, 128, 176, + 78, 51, 161, 151, 75, 248, 154, 31, 168, 9, 4, 3, 107, 222, 245, 178, 21, 84, 7, 25, + 155, 118, 97, 135, 63, 89, 233, 11, 207, 148, 155, 38, 106, 104, 102, 140, 104, 67, + 149, 20, 30, 196, 44, 197, 128, 34, 182, 80, 30, 32, 137, 34, 212, 164, 177, 164, 12, + 115, 41, 156, 111, 71, 230, 120, 111, 218, 25, 117, 218, 75, 167, 32, 37, 57, 50, 99, + 181, 203, 40, 105, 248, 150, 114, 121, 73, 127, 198, 191, 161, 44, 56, 213, 243, 71, 2, + 56, 192, 243, 107, 179, 27, 96, 21, 116, 169, 64, 15, 97, 166, 151, 200, 11, 40, 204, + 71, 168, 220, 9, 55, 43, 146, 244, 212, 166, 192, 180, 189, 237, 162, 42, 29, 33, 52, + 193, 4, 178, 157, 244, 28, 209, 44, 26, 36, 147, 126, 94, 164, 37, 47, 115, 38, 23, + 165, 96, 106, 140, 42, 69, 146, 194, 93, 71, 175, 49, 147, 32, 246, 97, 94, 41, 116, + 127, 174, 18, 16, 14, 163, 17, 180, 213, 203, 166, 33, 139, 214, 18, 170, 27, 41, 59, + 175, 200, 101, 14, 128, 45, 179, 167, 136, 232, 138, 56, 124, 145, 75, 233, 132, 161, + 196, 164, 72, 80, 60, 187, 38, 90, 90, 17, 66, 134, 59, 2, 165, 29, 76, 24, 38, 211, + 177, 83, 119, 20, 239, 59, 77, 34, 3, 42, 47, 60, 89, 46, 103, 168, 120, 17, 199, 50, + 17, 103, 107, 48, 8, 53, 220, 159, 212, 65, 198, 80, 8, 11, 235, 97, 203, 196, 240, 44, + 56, 121, 77, 91, 196, 160, 129, 242, 149, 226, 57, 106, 180, 76, 161, 203, 18, 37, 166, + 153, 44, 40, 28, 74, 8, 11, 6, 166, 54, 10, 103, 247, 23, 35, 7, 47, 173, 133, 71, 85, + 3, 168, 250, 120, 126, 174, 37, 80, 128, 107, 7, 161, 130, 155, 136, 92, 48, 215, 119, + 196, 124, 85, 157, 234, 2, 166, 137, 65, 121, 222, 112, 47, 17, 43, 23, 111, 88, 5, + 195, 41, 8, 191, 227, 21, 173, 35, 199, 196, 188, 162, 191, 195, 204, 137, 54, 16, 73, + 178, 150, 249, 234, 22, 216, 123, 157, 144, 218, 118, 53, 193, 67, 65, 84, 162, 244, + 165, 24, 110, 246, 146, 228, 212, 180, 150, 116, 201, 37, 128, 76, 41, 188, 42, 79, + 148, 52, 196, 176, 178, 224, 48, 168, 13, 129, 193, 131, 185, 131, 93, 40, 145, 56, + 180, 29, 153, 83, 39, 69, 232, 96, 238, 137, 104, 150, 2, 202, 239, 149, 248, 154, 115, + 115, 127, 3, 8, 32, 61, 96, 66, 25, 181, 14, 72, 73, 97, 186, 134, 140, 33, 69, 33, 74, + ]; + assert!(expected_ssk == keys.value.0.secret_spending_key); + assert!(expected_ccc == keys.ccc); + assert!(expected_nsk == keys.value.0.private_key_holder.nullifier_secret_key); + assert!(expected_npk == keys.value.0.nullifier_public_key); + assert!(expected_vsk == keys.value.0.private_key_holder.viewing_secret_key); + assert!(expected_vpk == keys.value.0.viewing_public_key.to_bytes()); + } + + #[test] + fn child_keys_generation() { + let seed: [u8; 64] = [ + 252, 56, 204, 83, 232, 123, 209, 188, 187, 167, 39, 213, 71, 39, 58, 65, 125, 134, 255, + 49, 43, 108, 92, 53, 173, 164, 94, 142, 150, 74, 21, 163, 43, 144, 226, 87, 199, 18, + 129, 223, 176, 198, 5, 150, 157, 70, 210, 254, 14, 105, 89, 191, 246, 27, 52, 170, 56, + 114, 39, 38, 118, 197, 205, 225, + ]; + + let root_node = ChildKeysPrivate::root(seed); + let child_node = ChildKeysPrivate::nth_child(&root_node, 42_u32); + + let expected_ssk = key_management::secret_holders::SecretSpendingKey([ + 151, 183, 113, 151, 215, 187, 207, 64, 197, 182, 207, 32, 5, 49, 180, 98, 119, 14, 248, + 175, 39, 100, 47, 109, 148, 173, 217, 253, 159, 234, 209, 113, + ]); + + let expected_ccc = [ + 138, 243, 142, 163, 62, 107, 63, 131, 230, 158, 185, 60, 204, 50, 243, 222, 13, 123, + 98, 116, 131, 194, 7, 25, 129, 209, 163, 72, 178, 143, 192, 240, + ]; + + let expected_nsk: NullifierSecretKey = [ + 196, 33, 11, 39, 220, 84, 119, 182, 187, 194, 135, 20, 124, 33, 244, 205, 96, 58, 102, + 52, 74, 67, 110, 213, 24, 16, 160, 64, 247, 3, 107, 235, + ]; + let expected_npk = lee_core::NullifierPublicKey([ + 247, 253, 217, 86, 157, 208, 39, 172, 59, 190, 88, 165, 7, 173, 183, 106, 172, 211, 4, + 180, 51, 107, 177, 107, 51, 117, 231, 176, 200, 103, 1, 121, + ]); + + let expected_vsk = ViewingSecretKey::new( + [ + 185, 209, 179, 92, 7, 131, 98, 121, 215, 46, 154, 56, 238, 106, 162, 225, 83, 82, + 134, 3, 80, 186, 35, 178, 161, 204, 205, 163, 28, 19, 149, 18, + ], + [ + 174, 24, 72, 205, 129, 123, 131, 9, 146, 152, 224, 151, 10, 184, 224, 109, 94, 149, + 117, 60, 26, 10, 212, 125, 113, 147, 87, 67, 73, 26, 101, 193, + ], + ); + + let expected_vpk: [u8; 1184] = [ + 215, 229, 207, 120, 148, 177, 148, 197, 72, 222, 134, 3, 231, 146, 123, 226, 36, 84, + 232, 179, 205, 16, 241, 142, 9, 81, 58, 54, 12, 115, 148, 182, 19, 245, 22, 203, 57, + 71, 11, 204, 156, 130, 30, 170, 199, 201, 25, 2, 21, 34, 155, 136, 124, 145, 223, 128, + 177, 207, 92, 38, 252, 165, 118, 61, 128, 71, 154, 242, 105, 165, 52, 7, 6, 244, 120, + 227, 134, 191, 25, 169, 150, 123, 246, 138, 25, 196, 126, 156, 144, 33, 123, 120, 44, + 142, 89, 201, 49, 219, 205, 87, 236, 110, 64, 129, 102, 100, 155, 26, 101, 121, 42, + 236, 82, 111, 141, 117, 75, 71, 194, 73, 123, 170, 110, 69, 149, 107, 96, 195, 55, 122, + 140, 131, 106, 140, 156, 147, 75, 28, 128, 138, 113, 86, 37, 63, 173, 214, 200, 2, 214, + 84, 234, 176, 120, 252, 184, 99, 192, 65, 112, 150, 99, 26, 174, 187, 183, 187, 64, 90, + 248, 100, 66, 63, 195, 3, 44, 43, 128, 59, 149, 107, 66, 180, 67, 200, 183, 200, 36, + 91, 7, 65, 228, 159, 79, 44, 89, 35, 163, 145, 92, 227, 104, 2, 72, 5, 7, 193, 21, 51, + 116, 198, 184, 6, 192, 188, 68, 183, 163, 193, 142, 244, 217, 155, 197, 187, 189, 174, + 225, 45, 126, 112, 93, 194, 156, 102, 150, 1, 188, 222, 76, 108, 73, 149, 44, 28, 219, + 66, 95, 215, 204, 148, 217, 16, 36, 121, 112, 2, 51, 10, 195, 137, 12, 93, 203, 146, + 138, 211, 15, 201, 42, 72, 146, 186, 160, 222, 235, 127, 83, 48, 182, 49, 248, 29, 138, + 16, 32, 232, 179, 163, 187, 161, 174, 152, 187, 93, 76, 166, 48, 230, 219, 111, 123, + 181, 103, 130, 28, 109, 235, 115, 45, 57, 193, 206, 160, 17, 52, 92, 194, 25, 3, 80, + 97, 142, 249, 151, 94, 250, 95, 12, 57, 11, 165, 92, 47, 85, 182, 48, 22, 60, 97, 244, + 59, 194, 135, 180, 133, 106, 227, 56, 192, 60, 91, 15, 241, 146, 89, 240, 130, 219, + 202, 187, 43, 85, 98, 50, 104, 64, 114, 113, 80, 54, 69, 69, 5, 43, 90, 19, 0, 0, 188, + 251, 184, 70, 160, 18, 117, 76, 53, 209, 166, 96, 34, 224, 137, 115, 183, 168, 243, 19, + 1, 255, 4, 97, 162, 199, 104, 72, 213, 111, 62, 54, 172, 82, 184, 82, 143, 71, 99, 25, + 104, 74, 120, 70, 84, 235, 32, 22, 20, 218, 163, 77, 194, 125, 75, 22, 72, 236, 192, + 200, 107, 91, 156, 201, 10, 178, 87, 19, 181, 211, 91, 17, 145, 200, 17, 179, 65, 75, + 200, 186, 89, 144, 91, 184, 116, 214, 51, 91, 42, 162, 243, 202, 92, 18, 54, 0, 213, + 67, 149, 151, 51, 29, 220, 196, 160, 201, 68, 113, 210, 164, 175, 152, 121, 168, 231, + 161, 91, 132, 218, 1, 171, 176, 84, 100, 57, 1, 3, 2, 196, 194, 76, 181, 79, 171, 157, + 35, 162, 155, 192, 210, 149, 142, 120, 189, 127, 151, 96, 202, 225, 73, 242, 81, 112, + 237, 224, 155, 130, 130, 34, 196, 153, 131, 161, 113, 163, 172, 114, 48, 207, 32, 151, + 172, 83, 145, 79, 210, 100, 161, 92, 82, 216, 90, 104, 238, 212, 38, 50, 107, 17, 228, + 195, 190, 6, 151, 165, 148, 245, 102, 51, 8, 185, 8, 85, 59, 247, 219, 95, 219, 170, + 155, 233, 123, 27, 64, 251, 56, 24, 200, 16, 181, 212, 146, 61, 116, 106, 215, 214, 62, + 118, 27, 68, 233, 148, 73, 135, 199, 74, 184, 89, 159, 217, 139, 24, 208, 250, 30, 224, + 97, 185, 237, 193, 8, 216, 23, 186, 5, 50, 41, 161, 203, 22, 217, 23, 194, 191, 148, + 124, 10, 212, 171, 209, 210, 145, 184, 171, 74, 35, 220, 43, 145, 241, 23, 43, 92, 171, + 216, 43, 114, 77, 155, 147, 156, 86, 56, 170, 27, 1, 54, 182, 169, 96, 22, 201, 51, + 145, 94, 143, 133, 106, 47, 176, 112, 197, 197, 96, 80, 73, 164, 207, 179, 22, 229, + 171, 201, 223, 219, 13, 219, 1, 91, 224, 252, 171, 199, 217, 25, 60, 128, 135, 9, 71, + 105, 231, 86, 34, 21, 155, 50, 0, 105, 72, 117, 108, 175, 140, 9, 181, 249, 139, 97, 3, + 161, 66, 248, 42, 67, 113, 132, 8, 119, 232, 6, 169, 18, 157, 222, 53, 176, 56, 137, + 120, 18, 115, 199, 187, 112, 48, 223, 211, 206, 152, 252, 108, 179, 129, 20, 227, 248, + 183, 234, 87, 202, 49, 17, 69, 215, 118, 89, 188, 180, 33, 238, 245, 206, 40, 179, 129, + 242, 59, 73, 254, 117, 114, 250, 179, 103, 109, 250, 202, 99, 152, 2, 167, 130, 169, + 35, 71, 89, 211, 140, 71, 103, 154, 121, 108, 147, 191, 186, 73, 10, 73, 203, 23, 55, + 106, 144, 98, 227, 157, 25, 27, 81, 67, 11, 57, 88, 227, 116, 61, 100, 94, 23, 166, + 146, 57, 226, 72, 124, 33, 65, 226, 35, 167, 206, 156, 202, 213, 213, 158, 89, 249, + 181, 19, 113, 109, 217, 71, 168, 142, 180, 122, 30, 5, 54, 170, 155, 73, 56, 170, 124, + 139, 4, 165, 103, 82, 32, 183, 84, 7, 239, 117, 135, 239, 48, 24, 28, 210, 49, 137, 6, + 158, 65, 211, 113, 205, 135, 146, 83, 10, 46, 90, 27, 97, 135, 135, 185, 173, 69, 58, + 34, 247, 141, 150, 6, 158, 117, 23, 198, 139, 65, 81, 179, 187, 194, 247, 203, 127, + 106, 232, 119, 122, 215, 197, 110, 69, 203, 174, 227, 63, 185, 106, 14, 184, 104, 113, + 233, 83, 92, 104, 38, 188, 9, 135, 107, 108, 121, 193, 33, 209, 89, 39, 137, 17, 208, + 26, 21, 238, 169, 86, 181, 193, 153, 82, 8, 151, 53, 39, 88, 91, 252, 3, 33, 75, 127, + 9, 168, 53, 34, 1, 173, 202, 123, 157, 174, 170, 199, 254, 187, 196, 144, 37, 29, 48, + 112, 173, 107, 147, 155, 69, 134, 137, 156, 247, 123, 242, 72, 5, 43, 106, 89, 179, + 204, 41, 15, 60, 48, 78, 214, 180, 26, 170, 67, 71, 66, 146, 113, 220, 159, 153, 201, + 176, 116, 154, 21, 186, 33, 180, 72, 39, 187, 240, 80, 112, 132, 144, 173, 210, 12, 76, + 184, 146, 89, 178, 178, 82, 109, 71, 201, 241, 160, 207, 219, 124, 77, 2, 105, 124, + 178, 71, 3, 38, 64, 41, 83, 170, 137, 82, 242, 144, 76, 102, 82, 7, 25, 149, 141, 169, + 46, 4, 68, 40, 244, 146, 131, 107, 148, 18, 111, 85, 104, 243, 28, 75, 176, 249, 88, + 82, 123, 89, 29, 104, 135, 230, 117, 67, 26, 249, 108, 145, 76, 38, 175, 89, 185, 94, + 106, 128, 201, 150, 151, 194, 133, 21, 81, 213, 231, 15, 117, 44, 61, 86, 223, 162, 56, + 190, 166, 177, 157, 137, 60, 208, 155, 234, 158, 252, 30, + ]; + + assert!(expected_ssk == child_node.value.0.secret_spending_key); + assert!(expected_ccc == child_node.ccc); + assert!(expected_nsk == child_node.value.0.private_key_holder.nullifier_secret_key); + assert!(expected_npk == child_node.value.0.nullifier_public_key); + assert!(expected_vsk == child_node.value.0.private_key_holder.viewing_secret_key); + assert!(expected_vpk == child_node.value.0.viewing_public_key.to_bytes()); + } +} diff --git a/key_protocol/src/key_management/key_tree/keys_public.rs b/lee/key_protocol/src/key_management/key_tree/keys_public.rs similarity index 94% rename from key_protocol/src/key_management/key_tree/keys_public.rs rename to lee/key_protocol/src/key_management/key_tree/keys_public.rs index 4671795d..a8f97070 100644 --- a/key_protocol/src/key_management/key_tree/keys_public.rs +++ b/lee/key_protocol/src/key_management/key_tree/keys_public.rs @@ -6,8 +6,8 @@ use crate::key_management::key_tree::traits::KeyTreeNode; #[derive(Debug, Serialize, Deserialize, Clone)] #[cfg_attr(any(test, feature = "test_utils"), derive(PartialEq, Eq))] pub struct ChildKeysPublic { - pub csk: nssa::PrivateKey, - pub cpk: nssa::PublicKey, + pub csk: lee::PrivateKey, + pub cpk: lee::PublicKey, pub ccc: [u8; 32], /// Can be [`None`] if root. pub cci: Option, @@ -18,14 +18,14 @@ impl ChildKeysPublic { pub fn root(seed: [u8; 64]) -> Self { let hash_value = hmac_sha512::HMAC::mac(seed, "LEE_master_pub"); - let csk = nssa::PrivateKey::try_new( + let csk = lee::PrivateKey::try_new( *hash_value .first_chunk::<32>() .expect("hash_value is 64 bytes, must be safe to get first 32"), ) .expect("Expect a valid Private Key"); let ccc = *hash_value.last_chunk::<32>().unwrap(); - let cpk = nssa::PublicKey::new_from_private_key(&csk); + let cpk = lee::PublicKey::new_from_private_key(&csk); Self { csk, @@ -39,7 +39,7 @@ impl ChildKeysPublic { pub fn nth_child(&self, cci: u32) -> Self { let hash_value = self.compute_hash_value(cci); - let csk = nssa::PrivateKey::try_new({ + let csk = lee::PrivateKey::try_new({ let hash_value = hash_value .first_chunk::<32>() .expect("hash_value is 64 bytes, must be safe to get first 32"); @@ -58,7 +58,7 @@ impl ChildKeysPublic { .last_chunk::<32>() .expect("hash_value is 64 bytes, must be safe to get last 32"); - let cpk = nssa::PublicKey::new_from_private_key(&csk); + let cpk = lee::PublicKey::new_from_private_key(&csk); Self { csk, @@ -69,8 +69,8 @@ impl ChildKeysPublic { } #[must_use] - pub fn account_id(&self) -> nssa::AccountId { - nssa::AccountId::from(&self.cpk) + pub fn account_id(&self) -> lee::AccountId { + lee::AccountId::from(&self.cpk) } fn compute_hash_value(&self, cci: u32) -> [u8; 64] { @@ -101,7 +101,7 @@ impl ChildKeysPublic { clippy::single_char_lifetime_names, reason = "TODO add meaningful name" )] -impl<'a> From<&'a ChildKeysPublic> for &'a nssa::PrivateKey { +impl<'a> From<&'a ChildKeysPublic> for &'a lee::PrivateKey { fn from(value: &'a ChildKeysPublic) -> Self { &value.csk } @@ -116,14 +116,14 @@ impl KeyTreeNode for ChildKeysPublic { self.nth_child(cci) } - fn account_ids(&self) -> impl Iterator { + fn account_ids(&self) -> impl Iterator { std::iter::once(self.account_id()) } } #[cfg(test)] mod tests { - use nssa::{PrivateKey, PublicKey}; + use lee::{PrivateKey, PublicKey}; use super::*; diff --git a/key_protocol/src/key_management/key_tree/mod.rs b/lee/key_protocol/src/key_management/key_tree/mod.rs similarity index 94% rename from key_protocol/src/key_management/key_tree/mod.rs rename to lee/key_protocol/src/key_management/key_tree/mod.rs index 3635c65c..3d93427b 100644 --- a/key_protocol/src/key_management/key_tree/mod.rs +++ b/lee/key_protocol/src/key_management/key_tree/mod.rs @@ -1,8 +1,8 @@ use std::collections::BTreeMap; use anyhow::Result; -use nssa::{Account, AccountId}; -use nssa_core::Identifier; +use lee::{Account, AccountId}; +use lee_core::Identifier; use serde::{Deserialize, Serialize}; use crate::key_management::{ @@ -24,7 +24,7 @@ pub const DEPTH_SOFT_CAP: u32 = 20; #[cfg_attr(any(test, feature = "test_utils"), derive(PartialEq, Eq))] pub struct KeyTree { pub key_map: BTreeMap, - pub account_id_map: BTreeMap, + pub account_id_map: BTreeMap, } pub type KeyTreePublic = KeyTree; @@ -178,22 +178,22 @@ impl KeyTree { } #[must_use] - pub fn get_node(&self, account_id: nssa::AccountId) -> Option<&N> { + pub fn get_node(&self, account_id: lee::AccountId) -> Option<&N> { let chain_id = self.account_id_map.get(&account_id)?; self.key_map.get(chain_id) } - pub fn get_node_mut(&mut self, account_id: nssa::AccountId) -> Option<&mut N> { + pub fn get_node_mut(&mut self, account_id: lee::AccountId) -> Option<&mut N> { let chain_id = self.account_id_map.get(&account_id)?; self.key_map.get_mut(chain_id) } - pub fn insert(&mut self, account_id: nssa::AccountId, chain_index: ChainIndex, node: N) { + pub fn insert(&mut self, account_id: lee::AccountId, chain_index: ChainIndex, node: N) { self.account_id_map.insert(account_id, chain_index.clone()); self.key_map.insert(chain_index, node); } - pub fn remove(&mut self, addr: nssa::AccountId) -> Option { + pub fn remove(&mut self, addr: lee::AccountId) -> Option { let chain_index = self.account_id_map.remove(&addr)?; self.key_map.remove(&chain_index) } @@ -204,7 +204,7 @@ impl KeyTree { pub fn generate_new_public_node( &mut self, parent_cci: &ChainIndex, - ) -> Option<(nssa::AccountId, ChainIndex)> { + ) -> Option<(lee::AccountId, ChainIndex)> { let cci = self.generate_new_node(parent_cci)?; let node = self.key_map.get(&cci)?; let account_id = node.account_ids().next()?; @@ -213,7 +213,7 @@ impl KeyTree { /// Generate a new public key node using layered placement, returning the account ID and chain /// index. - pub fn generate_new_public_node_layered(&mut self) -> Option<(nssa::AccountId, ChainIndex)> { + pub fn generate_new_public_node_layered(&mut self) -> Option<(lee::AccountId, ChainIndex)> { let cci = self.generate_new_node_layered()?; let node = self.key_map.get(&cci)?; let account_id = node.account_ids().next()?; @@ -240,7 +240,7 @@ impl KeyTree { let address = node.account_id(); let node_acc = get_account(address).await?; - if node_acc == nssa::Account::default() { + if node_acc == lee::Account::default() { let addr = node.account_id(); self.remove(addr); } else { @@ -273,9 +273,9 @@ impl KeyTree { &mut self, cci: &ChainIndex, identifier: Identifier, - ) -> Option { + ) -> Option { let node = self.key_map.get(cci)?; - let account_id = nssa::AccountId::for_regular_private_account( + let account_id = lee::AccountId::for_regular_private_account( &node.value.0.nullifier_public_key, identifier, ); @@ -306,7 +306,7 @@ impl KeyTree { .value .1 .iter() - .all(|(_, acc)| acc == &nssa::Account::default()) + .all(|(_, acc)| acc == &lee::Account::default()) { let account_ids = node.account_ids(); self.key_map.remove(&id); @@ -328,8 +328,8 @@ mod tests { use std::{collections::HashSet, str::FromStr as _}; - use nssa::AccountId; - use nssa_core::PrivateAccountKind; + use lee::AccountId; + use lee_core::PrivateAccountKind; use super::*; @@ -544,9 +544,9 @@ mod tests { .unwrap(); acc.value.1.insert( PrivateAccountKind::Regular(0), - nssa::Account { + lee::Account { balance: 2, - ..nssa::Account::default() + ..lee::Account::default() }, ); @@ -556,9 +556,9 @@ mod tests { .unwrap(); acc.value.1.insert( PrivateAccountKind::Regular(0), - nssa::Account { + lee::Account { balance: 3, - ..nssa::Account::default() + ..lee::Account::default() }, ); @@ -568,9 +568,9 @@ mod tests { .unwrap(); acc.value.1.insert( PrivateAccountKind::Regular(0), - nssa::Account { + lee::Account { balance: 5, - ..nssa::Account::default() + ..lee::Account::default() }, ); @@ -580,9 +580,9 @@ mod tests { .unwrap(); acc.value.1.insert( PrivateAccountKind::Regular(0), - nssa::Account { + lee::Account { balance: 6, - ..nssa::Account::default() + ..lee::Account::default() }, ); diff --git a/key_protocol/src/key_management/key_tree/traits.rs b/lee/key_protocol/src/key_management/key_tree/traits.rs similarity index 71% rename from key_protocol/src/key_management/key_tree/traits.rs rename to lee/key_protocol/src/key_management/key_tree/traits.rs index 71ca4743..f8f850d0 100644 --- a/key_protocol/src/key_management/key_tree/traits.rs +++ b/lee/key_protocol/src/key_management/key_tree/traits.rs @@ -4,5 +4,5 @@ pub trait KeyTreeNode: Sized { #[must_use] fn derive_child(&self, cci: u32) -> Self; #[must_use] - fn account_ids(&self) -> impl Iterator; + fn account_ids(&self) -> impl Iterator; } diff --git a/key_protocol/src/key_management/mod.rs b/lee/key_protocol/src/key_management/mod.rs similarity index 76% rename from key_protocol/src/key_management/mod.rs rename to lee/key_protocol/src/key_management/mod.rs index ad98d7e2..459badf0 100644 --- a/key_protocol/src/key_management/mod.rs +++ b/lee/key_protocol/src/key_management/mod.rs @@ -1,4 +1,4 @@ -use nssa_core::{ +use lee_core::{ NullifierPublicKey, SharedSecretKey, encryption::{EphemeralPublicKey, ViewingPublicKey}, }; @@ -69,21 +69,15 @@ impl KeyChain { pub fn calculate_shared_secret_receiver( &self, ephemeral_public_key_sender: &EphemeralPublicKey, - index: Option, - ) -> SharedSecretKey { - SharedSecretKey::new( - self.secret_spending_key.generate_viewing_secret_key(index), - ephemeral_public_key_sender, - ) + ) -> Option { + let vsk = &self.private_key_holder.viewing_secret_key; + SharedSecretKey::decapsulate(ephemeral_public_key_sender, &vsk.d, &vsk.z) } } #[cfg(test)] mod tests { - use aes_gcm::aead::OsRng; use base58::ToBase58 as _; - use k256::{AffinePoint, elliptic_curve::group::GroupEncoding as _}; - use rand::RngCore as _; use super::*; use crate::key_management::{ @@ -106,14 +100,31 @@ mod tests { fn calculate_shared_secret_receiver() { let account_id_key_holder = KeyChain::new_os_random(); - // Generate a random ephemeral public key sender - let mut scalar = [0; 32]; - OsRng.fill_bytes(&mut scalar); - let ephemeral_public_key_sender = EphemeralPublicKey::from_scalar(scalar); + // Create a proper KEM ciphertext by encapsulating toward this key chain's VPK. + let (_, epk) = SharedSecretKey::encapsulate(&account_id_key_holder.viewing_public_key); - // Calculate shared secret - let _shared_secret = account_id_key_holder - .calculate_shared_secret_receiver(&ephemeral_public_key_sender, None); + let _shared_secret = account_id_key_holder.calculate_shared_secret_receiver(&epk); + } + + #[test] + fn calculate_shared_secret_receiver_returns_none_for_malformed_epk() { + let key_chain = KeyChain::new_os_random(); + + let short_epk = EphemeralPublicKey(vec![42_u8; 100]); + assert!( + key_chain + .calculate_shared_secret_receiver(&short_epk) + .is_none(), + "short EphemeralPublicKey must return None" + ); + + let long_epk = EphemeralPublicKey(vec![42_u8; 1089]); + assert!( + key_chain + .calculate_shared_secret_receiver(&long_epk) + .is_none(), + "long EphemeralPublicKey must return None" + ); } #[test] @@ -126,21 +137,15 @@ mod tests { let nullifier_public_key = utxo_secret_key_holder.generate_nullifier_public_key(); let viewing_public_key = utxo_secret_key_holder.generate_viewing_public_key(); - let pub_account_signing_key = nssa::PrivateKey::new_os_random(); + let pub_account_signing_key = lee::PrivateKey::new_os_random(); - let public_key = nssa::PublicKey::new_from_private_key(&pub_account_signing_key); + let public_key = lee::PublicKey::new_from_private_key(&pub_account_signing_key); - let account = nssa::AccountId::from(&public_key); + let account = lee::AccountId::from(&public_key); println!("======Prerequisites======"); println!(); - println!( - "Group generator {:?}", - hex::encode(AffinePoint::GENERATOR.to_bytes()) - ); - println!(); - println!("======Holders======"); println!(); @@ -188,14 +193,12 @@ mod tests { fn non_trivial_chain_index() { let keys = account_with_chain_index_2_for_tests(); - let eph_key_holder = EphemeralKeyHolder::new(&keys.nullifier_public_key); + let eph_key_holder = EphemeralKeyHolder::new(&keys.viewing_public_key); - let key_sender = eph_key_holder.calculate_shared_secret_sender(&keys.viewing_public_key); - let key_receiver = keys.calculate_shared_secret_receiver( - &eph_key_holder.generate_ephemeral_public_key(), - Some(2), - ); + let key_sender = eph_key_holder.calculate_shared_secret_sender(); + let key_receiver = + keys.calculate_shared_secret_receiver(eph_key_holder.ephemeral_public_key()); - assert_eq!(key_sender.0, key_receiver.0); + assert_eq!(key_sender.0, key_receiver.unwrap().0); } } diff --git a/key_protocol/src/key_management/secret_holders.rs b/lee/key_protocol/src/key_management/secret_holders.rs similarity index 72% rename from key_protocol/src/key_management/secret_holders.rs rename to lee/key_protocol/src/key_management/secret_holders.rs index f5e71ca8..7bda4ffb 100644 --- a/key_protocol/src/key_management/secret_holders.rs +++ b/lee/key_protocol/src/key_management/secret_holders.rs @@ -1,9 +1,7 @@ use bip39::Mnemonic; use common::HashType; -use nssa_core::{ - NullifierPublicKey, NullifierSecretKey, - encryption::{Scalar, ViewingPublicKey}, -}; +use lee_core::{NullifierPublicKey, NullifierSecretKey, encryption::ViewingPublicKey}; +use ml_kem; use rand::{RngCore as _, rngs::OsRng}; use serde::{Deserialize, Serialize}; use sha2::{Digest as _, digest::FixedOutput as _}; @@ -19,8 +17,20 @@ pub struct SeedHolder { /// Secret spending key object. Can produce `PrivateKeyHolder` objects. #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct SecretSpendingKey(pub [u8; 32]); +/// Viewing secret key: the FIPS 203 KEM seed split into its two 32-byte halves `d` and `z`, +/// from which the ML-KEM-768 decapsulation key is derived deterministically. +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct ViewingSecretKey { + pub d: [u8; 32], + pub z: [u8; 32], +} -pub type ViewingSecretKey = Scalar; +impl ViewingSecretKey { + #[must_use] + pub const fn new(d: [u8; 32], z: [u8; 32]) -> Self { + Self { d, z } + } +} /// Private key holder. Produces public keys. Can produce `account_id`. Can produce shared secret /// for recepient. @@ -73,10 +83,10 @@ impl SeedHolder { #[must_use] pub fn generate_secret_spending_key_hash(&self) -> HashType { - let mut hash = hmac_sha512::HMAC::mac(&self.seed, "NSSA_seed"); + let mut hash = hmac_sha512::HMAC::mac(&self.seed, "LEE_seed"); for _ in 1..2048 { - hash = hmac_sha512::HMAC::mac(hash, "NSSA_seed"); + hash = hmac_sha512::HMAC::mac(hash, "LEE_seed"); } // Safe unwrap @@ -114,7 +124,7 @@ impl SecretSpendingKey { #[must_use] #[expect(clippy::big_endian_bytes, reason = "BIP-032 uses big endian")] - pub fn generate_viewing_secret_key(&self, index: Option) -> ViewingSecretKey { + pub fn generate_viewing_secret_seed_key(&self, index: Option) -> ViewingSecretKey { const PREFIX: &[u8; 8] = b"LEE/keys"; const SUFFIX_1: &[u8; 1] = &[2]; const SUFFIX_2: &[u8; 19] = &[0; 19]; @@ -124,25 +134,57 @@ impl SecretSpendingKey { _ => index.expect("Expect a valid u32"), }; - let mut hasher = sha2::Sha256::new(); - hasher.update(PREFIX); - hasher.update(self.0); - hasher.update(SUFFIX_1); - hasher.update(index.to_be_bytes()); - hasher.update(SUFFIX_2); + let mut bytes: Vec = Vec::with_capacity(64); + bytes.extend_from_slice(PREFIX); + bytes.extend_from_slice(&self.0); + bytes.extend_from_slice(SUFFIX_1); + bytes.extend_from_slice(&index.to_be_bytes()); + bytes.extend_from_slice(SUFFIX_2); + let bytes: [u8; 64] = bytes + .try_into() + .expect("`generate_viewing_secret_seed_key`: bytes must be exactly 64"); - hasher.finalize_fixed().into() + let full_seed = hmac_sha512::HMAC::mac(bytes, b"LEE_viewing_seed"); + + ViewingSecretKey::new( + *full_seed + .first_chunk::<32>() + .expect("hash_value is 64 bytes, must be safe to get first 32"), + *full_seed + .last_chunk::<32>() + .expect("hash_value is 64 bytes, must be safe to get last 32"), + ) + } + + #[must_use] + pub const fn generate_viewing_secret_key(seed: [u8; 64]) -> ViewingSecretKey { + ViewingSecretKey::new( + *seed.first_chunk::<32>().expect("seed is 64 bytes"), + *seed.last_chunk::<32>().expect("seed is 64 bytes"), + ) } #[must_use] pub fn produce_private_key_holder(&self, index: Option) -> PrivateKeyHolder { PrivateKeyHolder { nullifier_secret_key: self.generate_nullifier_secret_key(index), - viewing_secret_key: self.generate_viewing_secret_key(index), + viewing_secret_key: self.generate_viewing_secret_seed_key(index), } } } +impl From<&ViewingSecretKey> for ViewingPublicKey { + fn from(sk: &ViewingSecretKey) -> Self { + use ml_kem::{Kem, KeyExport as _, MlKem768, Seed}; + let mut seed_bytes = [0_u8; 64]; + seed_bytes[..32].copy_from_slice(&sk.d); + seed_bytes[32..].copy_from_slice(&sk.z); + let dk = ::DecapsulationKey::from_seed(Seed::from(seed_bytes)); + Self::from_bytes(dk.encapsulation_key().to_bytes().to_vec()) + .expect("key_protocol::secret_holders::From<&ViewingSecretKey>: ML-KEM-768 encapsulation key is always 1184 bytes") + } +} + impl PrivateKeyHolder { #[must_use] pub fn generate_nullifier_public_key(&self) -> NullifierPublicKey { @@ -151,7 +193,7 @@ impl PrivateKeyHolder { #[must_use] pub fn generate_viewing_public_key(&self) -> ViewingPublicKey { - ViewingPublicKey::from_scalar(self.viewing_secret_key) + ViewingPublicKey::from(&self.viewing_secret_key) } } @@ -183,8 +225,7 @@ mod tests { assert_eq!(seed_holder.seed.len(), 64); let top_secret_key_holder = seed_holder.produce_top_secret_key_holder(); - - let _vsk = top_secret_key_holder.generate_viewing_secret_key(None); + let _vsk = top_secret_key_holder.generate_viewing_secret_seed_key(None); } #[test] diff --git a/key_protocol/src/lib.rs b/lee/key_protocol/src/lib.rs similarity index 100% rename from key_protocol/src/lib.rs rename to lee/key_protocol/src/lib.rs diff --git a/nssa/Cargo.toml b/lee/state_machine/Cargo.toml similarity index 84% rename from nssa/Cargo.toml rename to lee/state_machine/Cargo.toml index 80542f16..8777db09 100644 --- a/nssa/Cargo.toml +++ b/lee/state_machine/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "nssa" +name = "lee" version = "0.1.0" edition = "2024" license = { workspace = true } @@ -8,9 +8,10 @@ license = { workspace = true } workspace = true [dependencies] -nssa_core = { workspace = true, features = ["host"] } +lee_core = { workspace = true, features = ["host"] } clock_core.workspace = true faucet_core.workspace = true +bridge_core.workspace = true anyhow.workspace = true thiserror.workspace = true @@ -30,6 +31,7 @@ risc0-build = "3.0.3" risc0-binfmt = "3.0.2" [dev-dependencies] +lee_core = { workspace = true, features = ["test_utils"] } token_core.workspace = true authenticated_transfer_core.workspace = true test_program_methods.workspace = true diff --git a/nssa/build.rs b/lee/state_machine/build.rs similarity index 94% rename from nssa/build.rs rename to lee/state_machine/build.rs index ce39df93..5e8ac989 100644 --- a/nssa/build.rs +++ b/lee/state_machine/build.rs @@ -5,7 +5,7 @@ fn main() -> Result<(), Box> { let out_dir = PathBuf::from(env::var("OUT_DIR")?); let mod_dir = out_dir.join("program_methods"); let mod_file = mod_dir.join("mod.rs"); - let program_methods_dir = manifest_dir.join("../artifacts/program_methods/"); + let program_methods_dir = manifest_dir.join("../../artifacts/program_methods/"); println!("cargo:rerun-if-changed={}", program_methods_dir.display()); diff --git a/nssa/core/Cargo.toml b/lee/state_machine/core/Cargo.toml similarity index 76% rename from nssa/core/Cargo.toml rename to lee/state_machine/core/Cargo.toml index d9e80af4..6e1f0ff0 100644 --- a/nssa/core/Cargo.toml +++ b/lee/state_machine/core/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "nssa_core" +name = "lee_core" version = "0.1.0" edition = "2024" license = { workspace = true } @@ -16,7 +16,7 @@ thiserror.workspace = true bytemuck.workspace = true bytesize.workspace = true base58.workspace = true -k256 = { workspace = true, optional = true } +ml-kem = { workspace = true, optional = true, features = ["getrandom"] } chacha20 = { version = "0.10" } [dev-dependencies] @@ -24,4 +24,5 @@ serde_json.workspace = true [features] default = [] -host = ["dep:k256"] +host = ["dep:ml-kem"] +test_utils = ["host"] diff --git a/nssa/core/src/account.rs b/lee/state_machine/core/src/account.rs similarity index 100% rename from nssa/core/src/account.rs rename to lee/state_machine/core/src/account.rs diff --git a/nssa/core/src/account/data.rs b/lee/state_machine/core/src/account/data.rs similarity index 99% rename from nssa/core/src/account/data.rs rename to lee/state_machine/core/src/account/data.rs index 36f82653..272f0191 100644 --- a/nssa/core/src/account/data.rs +++ b/lee/state_machine/core/src/account/data.rs @@ -19,7 +19,7 @@ impl Data { #[cfg(feature = "host")] pub fn from_cursor( cursor: &mut std::io::Cursor<&[u8]>, - ) -> Result { + ) -> Result { use std::io::Read as _; let mut u32_bytes = [0_u8; 4]; diff --git a/nssa/core/src/circuit_io.rs b/lee/state_machine/core/src/circuit_io.rs similarity index 100% rename from nssa/core/src/circuit_io.rs rename to lee/state_machine/core/src/circuit_io.rs diff --git a/nssa/core/src/commitment.rs b/lee/state_machine/core/src/commitment.rs similarity index 96% rename from nssa/core/src/commitment.rs rename to lee/state_machine/core/src/commitment.rs index 73ccd703..7c81c12c 100644 --- a/nssa/core/src/commitment.rs +++ b/lee/state_machine/core/src/commitment.rs @@ -7,8 +7,9 @@ use crate::account::{Account, AccountId}; /// A commitment to all zero data. /// ```python /// from hashlib import sha256 +/// prefix = b"/LEE/v0.3/Commitment/\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" /// hasher = sha256() -/// hasher.update(bytes([0] * 32 + [0] * 32 + [0] * 16 + [0] * 16 + list(sha256().digest()))) +/// hasher.update(prefix + bytes([0] * 32 + [0] * 32 + [0] * 16 + [0] * 16 + list(sha256().digest()))) /// DUMMY_COMMITMENT = hasher.digest() /// ``` pub const DUMMY_COMMITMENT: Commitment = Commitment([ diff --git a/nssa/core/src/encoding.rs b/lee/state_machine/core/src/encoding.rs similarity index 93% rename from nssa/core/src/encoding.rs rename to lee/state_machine/core/src/encoding.rs index ac9317c2..59df4b06 100644 --- a/nssa/core/src/encoding.rs +++ b/lee/state_machine/core/src/encoding.rs @@ -7,9 +7,9 @@ use std::io::Read as _; #[cfg(feature = "host")] use crate::Nullifier; #[cfg(feature = "host")] -use crate::encryption::shared_key_derivation::Secp256k1Point; +use crate::encryption::EphemeralPublicKey; #[cfg(feature = "host")] -use crate::error::NssaCoreError; +use crate::error::LeeCoreError; use crate::{ Commitment, NullifierPublicKey, account::{Account, AccountId}, @@ -34,7 +34,7 @@ impl Account { /// Deserializes an account from a cursor. #[cfg(feature = "host")] - pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result { + pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result { use crate::account::{Nonce, data::Data}; let mut u32_bytes = [0_u8; 4]; @@ -81,7 +81,7 @@ impl Commitment { /// Deserializes a commitment from a cursor. #[cfg(feature = "host")] - pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result { + pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result { let mut bytes = [0_u8; 32]; cursor.read_exact(&mut bytes)?; Ok(Self(bytes)) @@ -109,7 +109,7 @@ impl Nullifier { } /// Deserializes a nullifier from a cursor. - pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result { + pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result { let mut bytes = [0_u8; 32]; cursor.read_exact(&mut bytes)?; Ok(Self(bytes)) @@ -143,7 +143,7 @@ impl Ciphertext { #[cfg(feature = "host")] /// Deserializes ciphertext from a cursor. - pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result { + pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result { let mut u32_bytes = [0; 4]; cursor.read_exact(&mut u32_bytes)?; @@ -158,16 +158,17 @@ impl Ciphertext { } #[cfg(feature = "host")] -impl Secp256k1Point { - /// Converts the point to bytes. +impl EphemeralPublicKey { + /// Serializes the ML-KEM-768 ciphertext to bytes (always 1088 bytes). #[must_use] - pub fn to_bytes(&self) -> [u8; 33] { - self.0.clone().try_into().unwrap() + pub fn to_bytes(&self) -> Vec { + self.0.clone() } - /// Deserializes a secp256k1 point from a cursor. - pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result { - let mut value = vec![0; 33]; + /// Deserializes an ML-KEM-768 ciphertext from a cursor. + /// Reads exactly 1088 bytes — the fixed ciphertext size for ML-KEM-768. + pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result { + let mut value = vec![0_u8; 1088]; cursor.read_exact(&mut value)?; Ok(Self(value)) } diff --git a/nssa/core/src/encryption/mod.rs b/lee/state_machine/core/src/encryption/mod.rs similarity index 74% rename from nssa/core/src/encryption/mod.rs rename to lee/state_machine/core/src/encryption/mod.rs index 4b675d0e..37745d4f 100644 --- a/nssa/core/src/encryption/mod.rs +++ b/lee/state_machine/core/src/encryption/mod.rs @@ -6,7 +6,7 @@ use chacha20::{ use risc0_zkvm::sha::{Impl, Sha256 as _}; use serde::{Deserialize, Serialize}; #[cfg(feature = "host")] -pub use shared_key_derivation::{EphemeralPublicKey, EphemeralSecretKey, ViewingPublicKey}; +pub use shared_key_derivation::{EphemeralPublicKey, MlKem768EncapsulationKey, ViewingPublicKey}; use crate::{Commitment, account::Account, program::PrivateAccountKind}; #[cfg(feature = "host")] @@ -71,7 +71,7 @@ impl EncryptionScheme { ) -> [u8; 32] { let mut bytes = Vec::new(); - bytes.extend_from_slice(b"NSSA/v0.2/KDF-SHA256/"); + bytes.extend_from_slice(b"LEE/v0.2/KDF-SHA256/"); bytes.extend_from_slice(&shared_secret.0); bytes.extend_from_slice(&commitment.to_byte_array()); bytes.extend_from_slice(&output_index.to_le_bytes()); @@ -154,4 +154,41 @@ mod tests { assert_eq!(account_ct.0.len(), pda_ct.0.len()); } + + /// Verifies the full account-note pipeline: ML-KEM-768 encapsulation/decapsulation + /// feeds the correct shared secret into the SHA-256 KDF and `ChaCha20` round-trip. + #[cfg(feature = "host")] + #[test] + fn kem_to_chacha20_round_trip() { + let d = [1_u8; 32]; + let z = [2_u8; 32]; + let vpk = shared_key_derivation::ViewingPublicKey::from_seed(&d, &z); + + let (sender_ss, epk) = SharedSecretKey::encapsulate(&vpk); + let receiver_ss = SharedSecretKey::decapsulate(&epk, &d, &z).unwrap(); + + let account = Account { + program_owner: [12_u32; 8], + balance: 999, + ..Account::default() + }; + let kind = PrivateAccountKind::Regular(0); + let commitment = crate::Commitment::new(&AccountId::new([7_u8; 32]), &account); + + let ct = EncryptionScheme::encrypt(&account, &kind, &sender_ss, &commitment, 0); + let (decoded_kind, decoded_account) = + EncryptionScheme::decrypt(&ct, &receiver_ss, &commitment, 0) + .expect("decryption must succeed with correct shared secret"); + + assert_eq!(decoded_account, account); + assert_eq!(decoded_kind, kind); + + // Wrong shared secret must not decrypt correctly. + let wrong_ss = SharedSecretKey([0_u8; 32]); + let bad = EncryptionScheme::decrypt(&ct, &wrong_ss, &commitment, 0); + assert!( + bad.is_none() || bad.is_some_and(|(_, a)| a.balance != 999), + "wrong shared secret must not produce the correct plaintext" + ); + } } diff --git a/lee/state_machine/core/src/encryption/shared_key_derivation.rs b/lee/state_machine/core/src/encryption/shared_key_derivation.rs new file mode 100644 index 00000000..a3b2fd32 --- /dev/null +++ b/lee/state_machine/core/src/encryption/shared_key_derivation.rs @@ -0,0 +1,232 @@ +use borsh::{BorshDeserialize, BorshSerialize}; +use ml_kem::{Decapsulate as _, Encapsulate as _, KeyExport as _, Seed}; +use serde::{Deserialize, Serialize}; + +use crate::SharedSecretKey; + +/// The ML-KEM-768 ciphertext produced during encapsulation; transmitted on-wire in place of the +/// former ECDH ephemeral public key. Always 1088 bytes for ML-KEM-768. +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize)] +pub struct EphemeralPublicKey(pub Vec); + +/// ML-KEM-768 encapsulation key bytes (1184 bytes, opaque to this crate). +#[derive( + Serialize, + Deserialize, + Clone, + Debug, + PartialEq, + Eq, + PartialOrd, + Ord, + BorshSerialize, + BorshDeserialize, +)] +pub struct MlKem768EncapsulationKey(Vec); + +pub type ViewingPublicKey = MlKem768EncapsulationKey; + +impl MlKem768EncapsulationKey { + /// Expected byte length of an ML-KEM-768 encapsulation key. + pub const LEN: usize = 1184; + + /// Construct from raw bytes, returning an error if the length is not [`Self::LEN`]. + pub fn from_bytes(bytes: Vec) -> Result { + if bytes.len() != Self::LEN { + return Err(crate::error::LeeCoreError::DeserializationError(format!( + "MlKem768EncapsulationKey must be {} bytes, got {}", + Self::LEN, + bytes.len() + ))); + } + Ok(Self(bytes)) + } + + #[must_use] + pub fn to_bytes(&self) -> &[u8] { + &self.0 + } + + /// Derive the ML-KEM-768 encapsulation key from the FIPS 203 seed halves `d` and `z`. + #[must_use] + pub fn from_seed(d: &[u8; 32], z: &[u8; 32]) -> Self { + let mut seed = Seed::default(); + seed[..32].copy_from_slice(d); + seed[32..].copy_from_slice(z); + let dk = ml_kem::DecapsulationKey768::from_seed(seed); + Self(dk.encapsulation_key().to_bytes().to_vec()) + } +} + +impl SharedSecretKey { + /// Sender: encapsulate a fresh shared secret toward `ek`. + /// + /// Returns `(shared_secret, ciphertext)`. The ciphertext must be included in the transaction + /// as the `EphemeralPublicKey`; the receiver recovers the same shared secret via + /// [`Self::decapsulate`]. + #[must_use] + pub fn encapsulate(ek: &MlKem768EncapsulationKey) -> (Self, EphemeralPublicKey) { + let ek_bytes: ml_kem::kem::Key = + ek.0.as_slice() + .try_into() + .expect("MlKem768EncapsulationKey must be 1184 bytes"); + let ek_obj = ml_kem::EncapsulationKey768::new(&ek_bytes).expect( + "MlKem768EncapsulationKey bytes must encode a valid ML-KEM-768 encapsulation key", + ); + let (ct, ss) = ek_obj.encapsulate(); + let ss_bytes: [u8; 32] = ss + .as_slice() + .try_into() + .expect("ML-KEM shared key is 32 bytes"); + (Self(ss_bytes), EphemeralPublicKey(ct.to_vec())) + } + + /// Deterministically encapsulate a shared secret toward `ek` for use in tests. + /// + /// The shared secret has no secret entropy — it is fully determined by `ek`, + /// `message_hash`, and `output_index`, all of which are public. This makes it + /// unsuitable for real encryption but useful for producing stable, reproducible + /// shared secrets in unit tests. Use a distinct `output_index` per output to + /// avoid EPK collisions across multiple outputs in the same test. + /// + /// For production use [`Self::encapsulate`], which draws randomness from the OS. + #[cfg(any(test, feature = "test_utils"))] + #[must_use] + pub fn encapsulate_deterministic( + ek: &MlKem768EncapsulationKey, + message_hash: &[u8; 32], + output_index: u32, + ) -> (Self, EphemeralPublicKey) { + use risc0_zkvm::sha::{Impl, Sha256 as _}; + + let mut input = Vec::with_capacity(36); + input.extend_from_slice(message_hash); + input.extend_from_slice(&output_index.to_le_bytes()); + let hash = Impl::hash_bytes(&input); + let m: ml_kem::B32 = + ml_kem::array::Array::try_from(hash.as_bytes()).expect("SHA-256 output is 32 bytes"); + + let ek_bytes: ml_kem::kem::Key = + ek.0.as_slice() + .try_into() + .expect("MlKem768EncapsulationKey must be 1184 bytes"); + let ek_obj = ml_kem::EncapsulationKey768::new(&ek_bytes).expect( + "MlKem768EncapsulationKey bytes must encode a valid ML-KEM-768 encapsulation key", + ); + let (ct, ss) = ek_obj.encapsulate_deterministic(&m); + let ss_bytes: [u8; 32] = ss + .as_slice() + .try_into() + .expect("ML-KEM shared key is 32 bytes"); + (Self(ss_bytes), EphemeralPublicKey(ct.to_vec())) + } + + /// Receiver: decapsulate the shared secret from a KEM ciphertext. + /// + /// Returns `None` if the `EphemeralPublicKey` is not exactly 1088 bytes — callers on + /// the wallet scan path should skip the output rather than panic on malformed chain data. + /// + /// `d` and `z` are the two 32-byte halves of the FIPS 203 `ViewingSecretKey` seed. + #[must_use] + pub fn decapsulate( + ciphertext: &EphemeralPublicKey, + d: &[u8; 32], + z: &[u8; 32], + ) -> Option { + let mut seed = Seed::default(); + seed[..32].copy_from_slice(d); + seed[32..].copy_from_slice(z); + let dk = ml_kem::DecapsulationKey768::from_seed(seed); + let ss = dk.decapsulate_slice(&ciphertext.0).ok()?; + let ss_bytes: [u8; 32] = ss + .as_slice() + .try_into() + .expect("ML-KEM shared key is 32 bytes"); + Some(Self(ss_bytes)) + } +} + +#[cfg(test)] +mod tests { + use ml_kem::KeyExport as _; + + use super::*; + + #[test] + fn encapsulate_decapsulate_round_trip() { + let d = [1_u8; 32]; + let z = [2_u8; 32]; + + let mut seed = Seed::default(); + seed[..32].copy_from_slice(&d); + seed[32..].copy_from_slice(&z); + + let dk = ml_kem::DecapsulationKey768::from_seed(seed); + let ek_bytes = dk.encapsulation_key().to_bytes(); + let ek = MlKem768EncapsulationKey(ek_bytes.to_vec()); + + let (sender_ss, epk) = SharedSecretKey::encapsulate(&ek); + let receiver_ss = SharedSecretKey::decapsulate(&epk, &d, &z).unwrap(); + + assert_eq!(sender_ss.0, receiver_ss.0, "shared secrets must match"); + assert_eq!(epk.0.len(), 1088, "ML-KEM-768 ciphertext is 1088 bytes"); + assert_eq!( + ek.0.len(), + 1184, + "ML-KEM-768 encapsulation key is 1184 bytes" + ); + } + + #[test] + fn decapsulate_returns_none_for_malformed_epk() { + let d = [1_u8; 32]; + let z = [2_u8; 32]; + + // Too short — 100 bytes instead of 1088. + let short_epk = EphemeralPublicKey(vec![42_u8; 100]); + assert!( + SharedSecretKey::decapsulate(&short_epk, &d, &z).is_none(), + "short EphemeralPublicKey must return None" + ); + + // Too long — 1089 bytes instead of 1088. + let long_epk = EphemeralPublicKey(vec![42_u8; 1089]); + assert!( + SharedSecretKey::decapsulate(&long_epk, &d, &z).is_none(), + "long EphemeralPublicKey must return None" + ); + + // Empty. + let empty_epk = EphemeralPublicKey(vec![]); + assert!( + SharedSecretKey::decapsulate(&empty_epk, &d, &z).is_none(), + "empty EphemeralPublicKey must return None" + ); + } + + #[test] + fn different_vpks_produce_different_shared_secrets() { + let (d1, z1) = ([1_u8; 32], [2_u8; 32]); + let (d2, z2) = ([3_u8; 32], [4_u8; 32]); + + let ek1 = { + let mut seed = Seed::default(); + seed[..32].copy_from_slice(&d1); + seed[32..].copy_from_slice(&z1); + let dk = ml_kem::DecapsulationKey768::from_seed(seed); + MlKem768EncapsulationKey(dk.encapsulation_key().to_bytes().to_vec()) + }; + let ek2 = { + let mut seed = Seed::default(); + seed[..32].copy_from_slice(&d2); + seed[32..].copy_from_slice(&z2); + let dk = ml_kem::DecapsulationKey768::from_seed(seed); + MlKem768EncapsulationKey(dk.encapsulation_key().to_bytes().to_vec()) + }; + + let (ss1, _) = SharedSecretKey::encapsulate(&ek1); + let (ss2, _) = SharedSecretKey::encapsulate(&ek2); + + assert_ne!(ss1.0, ss2.0); + } +} diff --git a/nssa/core/src/error.rs b/lee/state_machine/core/src/error.rs similarity index 88% rename from nssa/core/src/error.rs rename to lee/state_machine/core/src/error.rs index 8f053233..c426aee1 100644 --- a/nssa/core/src/error.rs +++ b/lee/state_machine/core/src/error.rs @@ -3,7 +3,7 @@ use std::io; use thiserror::Error; #[derive(Error, Debug)] -pub enum NssaCoreError { +pub enum LeeCoreError { #[error("Deserialization error: {0}")] DeserializationError(String), diff --git a/nssa/core/src/lib.rs b/lee/state_machine/core/src/lib.rs similarity index 100% rename from nssa/core/src/lib.rs rename to lee/state_machine/core/src/lib.rs diff --git a/nssa/core/src/nullifier.rs b/lee/state_machine/core/src/nullifier.rs similarity index 100% rename from nssa/core/src/nullifier.rs rename to lee/state_machine/core/src/nullifier.rs diff --git a/nssa/core/src/program.rs b/lee/state_machine/core/src/program.rs similarity index 99% rename from nssa/core/src/program.rs rename to lee/state_machine/core/src/program.rs index 27ad9b8b..c5949dcf 100644 --- a/nssa/core/src/program.rs +++ b/lee/state_machine/core/src/program.rs @@ -126,7 +126,7 @@ impl AccountId { pub fn for_public_pda(program_id: &ProgramId, seed: &PdaSeed) -> Self { use risc0_zkvm::sha::{Impl, Sha256 as _}; const PROGRAM_DERIVED_ACCOUNT_ID_PREFIX: &[u8; 32] = - b"/NSSA/v0.2/AccountId/PDA/\x00\x00\x00\x00\x00\x00\x00"; + b"/LEE/v0.2/AccountId/PDA/\x00\x00\x00\x00\x00\x00\x00\x00"; let mut bytes = [0; 96]; bytes[0..32].copy_from_slice(PROGRAM_DERIVED_ACCOUNT_ID_PREFIX); @@ -635,9 +635,9 @@ pub fn compute_public_authorized_pdas( .collect() } -/// Reads the NSSA inputs from the guest environment. +/// Reads the LEE inputs from the guest environment. #[must_use] -pub fn read_nssa_inputs() -> (ProgramInput, InstructionData) { +pub fn read_lee_inputs() -> (ProgramInput, InstructionData) { let self_program_id: ProgramId = env::read(); let caller_program_id: Option = env::read(); let pre_states: Vec = env::read(); diff --git a/nssa/rust-toolchain.toml b/lee/state_machine/rust-toolchain.toml similarity index 100% rename from nssa/rust-toolchain.toml rename to lee/state_machine/rust-toolchain.toml diff --git a/nssa/src/encoding/mod.rs b/lee/state_machine/src/encoding/mod.rs similarity index 100% rename from nssa/src/encoding/mod.rs rename to lee/state_machine/src/encoding/mod.rs diff --git a/nssa/src/encoding/privacy_preserving_transaction.rs b/lee/state_machine/src/encoding/privacy_preserving_transaction.rs similarity index 65% rename from nssa/src/encoding/privacy_preserving_transaction.rs rename to lee/state_machine/src/encoding/privacy_preserving_transaction.rs index 6fe5c443..b50447b2 100644 --- a/nssa/src/encoding/privacy_preserving_transaction.rs +++ b/lee/state_machine/src/encoding/privacy_preserving_transaction.rs @@ -1,6 +1,5 @@ use crate::{ - PrivacyPreservingTransaction, error::NssaError, - privacy_preserving_transaction::message::Message, + PrivacyPreservingTransaction, error::LeeError, privacy_preserving_transaction::message::Message, }; impl Message { @@ -9,7 +8,7 @@ impl Message { borsh::to_vec(&self).expect("Autoderived borsh serialization failure") } - pub fn from_bytes(bytes: &[u8]) -> Result { + pub fn from_bytes(bytes: &[u8]) -> Result { Ok(borsh::from_slice(bytes)?) } } @@ -20,7 +19,7 @@ impl PrivacyPreservingTransaction { borsh::to_vec(&self).expect("Autoderived borsh serialization failure") } - pub fn from_bytes(bytes: &[u8]) -> Result { + pub fn from_bytes(bytes: &[u8]) -> Result { Ok(borsh::from_slice(bytes)?) } } diff --git a/nssa/src/encoding/program_deployment_transaction.rs b/lee/state_machine/src/encoding/program_deployment_transaction.rs similarity index 84% rename from nssa/src/encoding/program_deployment_transaction.rs rename to lee/state_machine/src/encoding/program_deployment_transaction.rs index fc1bf459..05688086 100644 --- a/nssa/src/encoding/program_deployment_transaction.rs +++ b/lee/state_machine/src/encoding/program_deployment_transaction.rs @@ -1,4 +1,4 @@ -use crate::{ProgramDeploymentTransaction, error::NssaError}; +use crate::{ProgramDeploymentTransaction, error::LeeError}; impl ProgramDeploymentTransaction { #[must_use] @@ -6,7 +6,7 @@ impl ProgramDeploymentTransaction { borsh::to_vec(&self).expect("Autoderived borsh serialization failure") } - pub fn from_bytes(bytes: &[u8]) -> Result { + pub fn from_bytes(bytes: &[u8]) -> Result { Ok(borsh::from_slice(bytes)?) } } diff --git a/nssa/src/encoding/public_transaction.rs b/lee/state_machine/src/encoding/public_transaction.rs similarity index 71% rename from nssa/src/encoding/public_transaction.rs rename to lee/state_machine/src/encoding/public_transaction.rs index 2549cf27..493d9a90 100644 --- a/nssa/src/encoding/public_transaction.rs +++ b/lee/state_machine/src/encoding/public_transaction.rs @@ -1,4 +1,4 @@ -use crate::{PublicTransaction, error::NssaError, public_transaction::Message}; +use crate::{PublicTransaction, error::LeeError, public_transaction::Message}; impl Message { pub(crate) fn to_bytes(&self) -> Vec { @@ -12,7 +12,7 @@ impl PublicTransaction { borsh::to_vec(&self).expect("Autoderived borsh serialization failure") } - pub fn from_bytes(bytes: &[u8]) -> Result { + pub fn from_bytes(bytes: &[u8]) -> Result { Ok(borsh::from_slice(bytes)?) } } diff --git a/nssa/src/error.rs b/lee/state_machine/src/error.rs similarity index 92% rename from nssa/src/error.rs rename to lee/state_machine/src/error.rs index 65079d25..2f073746 100644 --- a/nssa/src/error.rs +++ b/lee/state_machine/src/error.rs @@ -1,6 +1,6 @@ use std::io; -use nssa_core::{ +use lee_core::{ account::{Account, AccountId}, program::ProgramId, }; @@ -16,7 +16,7 @@ macro_rules! ensure { } #[derive(Error, Debug)] -pub enum NssaError { +pub enum LeeError { #[error("Invalid input: {0}")] InvalidInput(String), @@ -51,7 +51,7 @@ pub enum NssaError { TransactionDeserializationError(String), #[error("Core error")] - Core(#[from] nssa_core::error::NssaCoreError), + Core(#[from] lee_core::error::LeeCoreError), #[error("Program output deserialization error: {0}")] ProgramOutputDeserializationError(String), @@ -96,6 +96,9 @@ pub enum InvalidProgramBehaviorError { #[error("Unauthorized account marked as authorized")] InvalidAccountAuthorization { account_id: AccountId }, + #[error("Authorized account marked as not authorized")] + AuthorizedAccountMarkedAsNotAuthorized { account_id: AccountId }, + #[error("Program ID mismatch: expected {expected:?}, actual {actual:?}")] MismatchedProgramId { expected: ProgramId, @@ -109,7 +112,7 @@ pub enum InvalidProgramBehaviorError { }, #[error(transparent)] - ExecutionValidationFailed(#[from] nssa_core::program::ExecutionValidationError), + ExecutionValidationFailed(#[from] lee_core::program::ExecutionValidationError), #[error("Trying to claim account {account_id} which is not default")] ClaimedNonDefaultAccount { account_id: AccountId }, diff --git a/nssa/src/lib.rs b/lee/state_machine/src/lib.rs similarity index 90% rename from nssa/src/lib.rs rename to lee/state_machine/src/lib.rs index 5998e803..129821b5 100644 --- a/nssa/src/lib.rs +++ b/lee/state_machine/src/lib.rs @@ -3,7 +3,7 @@ reason = "We prefer to group methods by functionality rather than by type for encoding" )] -pub use nssa_core::{ +pub use lee_core::{ GENESIS_BLOCK_ID, SharedSecretKey, account::{Account, AccountId, Data}, encryption::EphemeralPublicKey, @@ -18,7 +18,7 @@ pub use public_transaction::PublicTransaction; pub use signature::{PrivateKey, PublicKey, Signature}; pub use state::{ CLOCK_01_PROGRAM_ACCOUNT_ID, CLOCK_10_PROGRAM_ACCOUNT_ID, CLOCK_50_PROGRAM_ACCOUNT_ID, - CLOCK_PROGRAM_ACCOUNT_IDS, V03State, system_faucet_account_id, + CLOCK_PROGRAM_ACCOUNT_IDS, V03State, system_bridge_account_id, system_faucet_account_id, }; pub use validated_state_diff::ValidatedStateDiff; diff --git a/nssa/src/merkle_tree/default_values.rs b/lee/state_machine/src/merkle_tree/default_values.rs similarity index 100% rename from nssa/src/merkle_tree/default_values.rs rename to lee/state_machine/src/merkle_tree/default_values.rs diff --git a/nssa/src/merkle_tree/mod.rs b/lee/state_machine/src/merkle_tree/mod.rs similarity index 100% rename from nssa/src/merkle_tree/mod.rs rename to lee/state_machine/src/merkle_tree/mod.rs diff --git a/nssa/src/privacy_preserving_transaction/circuit.rs b/lee/state_machine/src/privacy_preserving_transaction/circuit.rs similarity index 92% rename from nssa/src/privacy_preserving_transaction/circuit.rs rename to lee/state_machine/src/privacy_preserving_transaction/circuit.rs index 902f5eaa..50202a38 100644 --- a/nssa/src/privacy_preserving_transaction/circuit.rs +++ b/lee/state_machine/src/privacy_preserving_transaction/circuit.rs @@ -1,7 +1,7 @@ use std::collections::{HashMap, VecDeque}; use borsh::{BorshDeserialize, BorshSerialize}; -use nssa_core::{ +use lee_core::{ InputAccountIdentity, PrivacyPreservingCircuitInput, PrivacyPreservingCircuitOutput, account::AccountWithMetadata, program::{ChainedCall, InstructionData, ProgramId, ProgramOutput}, @@ -9,7 +9,7 @@ use nssa_core::{ use risc0_zkvm::{ExecutorEnv, InnerReceipt, ProverOpts, Receipt, default_prover}; use crate::{ - error::{InvalidProgramBehaviorError, NssaError}, + error::{InvalidProgramBehaviorError, LeeError}, program::Program, program_methods::{PRIVACY_PRESERVING_CIRCUIT_ELF, PRIVACY_PRESERVING_CIRCUIT_ID}, state::MAX_NUMBER_CHAINED_CALLS, @@ -60,14 +60,14 @@ impl From for ProgramWithDependencies { } } -/// Generates a proof of the execution of a NSSA program inside the privacy preserving execution +/// Generates a proof of the execution of a LEE program inside the privacy preserving execution /// circuit. pub fn execute_and_prove( pre_states: Vec, instruction_data: InstructionData, account_identities: Vec, program_with_dependencies: &ProgramWithDependencies, -) -> Result<(PrivacyPreservingCircuitOutput, Proof), NssaError> { +) -> Result<(PrivacyPreservingCircuitOutput, Proof), LeeError> { let ProgramWithDependencies { program: initial_program, dependencies, @@ -86,7 +86,7 @@ pub fn execute_and_prove( let mut chain_calls_counter = 0; while let Some((chained_call, program, caller_program_id)) = chained_calls.pop_front() { if chain_calls_counter >= MAX_NUMBER_CHAINED_CALLS { - return Err(NssaError::MaxChainedCallsDepthExceeded); + return Err(LeeError::MaxChainedCallsDepthExceeded); } let inner_receipt = execute_and_prove_program( @@ -99,7 +99,7 @@ pub fn execute_and_prove( let program_output: ProgramOutput = inner_receipt .journal .decode() - .map_err(|e| NssaError::ProgramOutputDeserializationError(e.to_string()))?; + .map_err(|e| LeeError::ProgramOutputDeserializationError(e.to_string()))?; // TODO: remove clone program_outputs.push(program_output.clone()); @@ -133,7 +133,7 @@ pub fn execute_and_prove( let opts = ProverOpts::succinct(); let prove_info = prover .prove_with_opts(env, PRIVACY_PRESERVING_CIRCUIT_ELF, &opts) - .map_err(|e| NssaError::CircuitProvingError(e.to_string()))?; + .map_err(|e| LeeError::CircuitProvingError(e.to_string()))?; let proof = Proof(borsh::to_vec(&prove_info.receipt.inner)?); @@ -141,7 +141,7 @@ pub fn execute_and_prove( .receipt .journal .decode() - .map_err(|e| NssaError::CircuitOutputDeserializationError(e.to_string()))?; + .map_err(|e| LeeError::CircuitOutputDeserializationError(e.to_string()))?; Ok((circuit_output, proof)) } @@ -151,7 +151,7 @@ fn execute_and_prove_program( caller_program_id: Option, pre_states: &[AccountWithMetadata], instruction_data: &InstructionData, -) -> Result { +) -> Result { // Write inputs to the program let mut env_builder = ExecutorEnv::builder(); Program::write_inputs( @@ -167,7 +167,7 @@ fn execute_and_prove_program( let prover = default_prover(); Ok(prover .prove(env, program.elf()) - .map_err(|e| NssaError::ProgramProveFailed(e.to_string()))? + .map_err(|e| LeeError::ProgramProveFailed(e.to_string()))? .receipt) } @@ -175,7 +175,7 @@ fn execute_and_prove_program( mod tests { #![expect(clippy::shadow_unrelated, reason = "We don't care about it in tests")] - use nssa_core::{ + use lee_core::{ Commitment, DUMMY_COMMITMENT_HASH, EncryptionScheme, Nullifier, PrivacyPreservingCircuitOutput, SharedSecretKey, account::{Account, AccountId, AccountWithMetadata, Nonce, data::Data}, @@ -184,7 +184,7 @@ mod tests { use super::*; use crate::{ - error::NssaError, + error::LeeError, privacy_preserving_transaction::circuit::execute_and_prove, program::Program, state::{ @@ -243,8 +243,8 @@ mod tests { let expected_sender_pre = sender.clone(); - let esk = [3; 32]; - let shared_secret = SharedSecretKey::new(esk, &recipient_keys.vpk()); + let shared_secret = + SharedSecretKey::encapsulate_deterministic(&recipient_keys.vpk(), &[0_u8; 32], 0).0; let (output, proof) = execute_and_prove( vec![sender, recipient], @@ -340,11 +340,11 @@ mod tests { Commitment::new(&recipient_account_id, &expected_private_account_2), ]; - let esk_1 = [3; 32]; - let shared_secret_1 = SharedSecretKey::new(esk_1, &sender_keys.vpk()); + let shared_secret_1 = + SharedSecretKey::encapsulate_deterministic(&sender_keys.vpk(), &[0_u8; 32], 0).0; - let esk_2 = [5; 32]; - let shared_secret_2 = SharedSecretKey::new(esk_2, &recipient_keys.vpk()); + let shared_secret_2 = + SharedSecretKey::encapsulate_deterministic(&recipient_keys.vpk(), &[0_u8; 32], 1).0; let (output, proof) = execute_and_prove( vec![sender_pre, recipient], @@ -418,8 +418,8 @@ mod tests { )) .unwrap(); - let esk = [3; 32]; - let shared_secret = SharedSecretKey::new(esk, &account_keys.vpk()); + let shared_secret = + SharedSecretKey::encapsulate_deterministic(&account_keys.vpk(), &[0_u8; 32], 0).0; let program_with_deps = ProgramWithDependencies::new( validity_window_chain_caller, @@ -437,7 +437,7 @@ mod tests { &program_with_deps, ); - assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + assert!(matches!(result, Err(LeeError::CircuitProvingError(_)))); } /// A private PDA claimed with a non-default identifier produces a ciphertext that decrypts @@ -449,7 +449,8 @@ mod tests { let npk = keys.npk(); let seed = PdaSeed::new([42; 32]); let identifier: u128 = 99; - let shared_secret = SharedSecretKey::new([55; 32], &keys.vpk()); + let shared_secret = + SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0; let account_id = AccountId::for_private_pda(&program.id(), &seed, &npk, identifier); let pre_state = AccountWithMetadata::new(Account::default(), false, account_id); @@ -487,7 +488,8 @@ mod tests { let keys = test_private_account_keys_1(); let npk = keys.npk(); let seed = PdaSeed::new([42; 32]); - let shared_secret_pda = SharedSecretKey::new([55; 32], &keys.vpk()); + let shared_secret_pda = + SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0; // PDA (new, private PDA) let pda_id = AccountId::for_private_pda(&program.id(), &seed, &npk, 0); @@ -526,7 +528,8 @@ mod tests { let keys = test_private_account_keys_1(); let npk = keys.npk(); let seed = PdaSeed::new([42; 32]); - let shared_secret_pda = SharedSecretKey::new([55; 32], &keys.vpk()); + let shared_secret_pda = + SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0; // PDA (new, private PDA) let pda_id = AccountId::for_private_pda(&program.id(), &seed, &npk, 0); @@ -581,7 +584,8 @@ mod tests { let shared_keys = test_private_account_keys_1(); let shared_npk = shared_keys.npk(); let shared_identifier: u128 = 42; - let shared_secret = SharedSecretKey::new([55; 32], &shared_keys.vpk()); + let shared_secret = + SharedSecretKey::encapsulate_deterministic(&shared_keys.vpk(), &[0_u8; 32], 0).0; // Sender: public account with balance, owned by auth-transfer let sender_id = AccountId::new([99; 32]); @@ -632,7 +636,7 @@ mod tests { let program = Program::authenticated_transfer_program(); let keys = test_private_account_keys_1(); let identifier: u128 = 99; - let ssk = SharedSecretKey::new([55; 32], &keys.vpk()); + let ssk = SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0; let account_id = AccountId::for_regular_private_account(&keys.npk(), identifier); let pre = AccountWithMetadata::new(Account::default(), true, account_id); @@ -662,7 +666,7 @@ mod tests { let program = Program::authenticated_transfer_program(); let keys = test_private_account_keys_1(); let identifier: u128 = 99; - let ssk = SharedSecretKey::new([55; 32], &keys.vpk()); + let ssk = SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0; let sender = AccountWithMetadata::new( Account { @@ -707,7 +711,7 @@ mod tests { let program = Program::authenticated_transfer_program(); let keys = test_private_account_keys_1(); let identifier: u128 = 99; - let ssk = SharedSecretKey::new([55; 32], &keys.vpk()); + let ssk = SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0; let account_id = AccountId::for_regular_private_account(&keys.npk(), identifier); let account = Account { program_owner: program.id(), @@ -756,7 +760,7 @@ mod tests { let npk = keys.npk(); let seed = PdaSeed::new([42; 32]); let identifier: u128 = 99; - let ssk = SharedSecretKey::new([55; 32], &keys.vpk()); + let ssk = SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0; let auth_transfer_id = auth_transfer.id(); let pda_id = AccountId::for_private_pda(&program.id(), &seed, &npk, identifier); @@ -811,7 +815,8 @@ mod tests { let keys = test_private_account_keys_1(); let npk = keys.npk(); let seed = PdaSeed::new([42; 32]); - let shared_secret = SharedSecretKey::new([55; 32], &keys.vpk()); + let shared_secret = + SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0; let account_id = AccountId::for_private_pda(&program.id(), &seed, &npk, 5); let pre_state = AccountWithMetadata::new(Account::default(), false, account_id); @@ -828,7 +833,7 @@ mod tests { &program.into(), ); - assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + assert!(matches!(result, Err(LeeError::CircuitProvingError(_)))); } #[test] @@ -838,7 +843,7 @@ mod tests { let keys = test_private_account_keys_1(); let npk = keys.npk(); let seed = PdaSeed::new([42; 32]); - let ssk = SharedSecretKey::new([55; 32], &keys.vpk()); + let ssk = SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0; let auth_transfer_id = auth_transfer.id(); let pda_id = AccountId::for_private_pda(&program.id(), &seed, &npk, 5); @@ -874,6 +879,6 @@ mod tests { &program_with_deps, ); - assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + assert!(matches!(result, Err(LeeError::CircuitProvingError(_)))); } } diff --git a/nssa/src/privacy_preserving_transaction/message.rs b/lee/state_machine/src/privacy_preserving_transaction/message.rs similarity index 92% rename from nssa/src/privacy_preserving_transaction/message.rs rename to lee/state_machine/src/privacy_preserving_transaction/message.rs index 3a968bfb..6a289a0a 100644 --- a/nssa/src/privacy_preserving_transaction/message.rs +++ b/lee/state_machine/src/privacy_preserving_transaction/message.rs @@ -1,5 +1,5 @@ use borsh::{BorshDeserialize, BorshSerialize}; -use nssa_core::{ +use lee_core::{ Commitment, CommitmentSetDigest, Nullifier, NullifierPublicKey, PrivacyPreservingCircuitOutput, account::{Account, Nonce}, encryption::{Ciphertext, EphemeralPublicKey, ViewingPublicKey}, @@ -7,7 +7,7 @@ use nssa_core::{ }; use sha2::{Digest as _, Sha256}; -use crate::{AccountId, error::NssaError}; +use crate::{AccountId, error::LeeError}; const PREFIX: &[u8; 32] = b"/LEE/v0.3/Message/Privacy/\x00\x00\x00\x00\x00\x00"; @@ -94,9 +94,9 @@ impl Message { nonces: Vec, public_keys: Vec<(NullifierPublicKey, ViewingPublicKey, EphemeralPublicKey)>, output: PrivacyPreservingCircuitOutput, - ) -> Result { + ) -> Result { if public_keys.len() != output.ciphertexts.len() { - return Err(NssaError::InvalidInput( + return Err(LeeError::InvalidInput( "Ephemeral public keys and ciphertexts length mismatch".into(), )); } @@ -139,11 +139,11 @@ impl Message { #[cfg(test)] pub mod tests { - use nssa_core::{ + use lee_core::{ Commitment, EncryptionScheme, Nullifier, NullifierPublicKey, PrivateAccountKind, SharedSecretKey, account::{Account, AccountId, Nonce}, - encryption::{EphemeralPublicKey, ViewingPublicKey}, + encryption::ViewingPublicKey, program::{BlockValidityWindow, TimestampValidityWindow}, }; use sha2::{Digest as _, Sha256}; @@ -169,10 +169,10 @@ pub mod tests { let encrypted_private_post_states = Vec::new(); - let account_id2 = nssa_core::account::AccountId::for_regular_private_account(&npk2, 0); + let account_id2 = lee_core::account::AccountId::for_regular_private_account(&npk2, 0); let new_commitments = vec![Commitment::new(&account_id2, &account2)]; - let account_id1 = nssa_core::account::AccountId::for_regular_private_account(&npk1, 0); + let account_id1 = lee_core::account::AccountId::for_regular_private_account(&npk1, 0); let old_commitment = Commitment::new(&account_id1, &account1); let new_nullifiers = vec![( Nullifier::for_account_update(&old_commitment, &nsk1), @@ -208,7 +208,7 @@ pub mod tests { let nonces_bytes: &[u8] = &[1, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // all remaining vec fields are empty: u32 len=0 let empty_vec_bytes: &[u8] = &[0_u8; 4]; - // validity windows: unbounded = {from: None (0u8), to: None (0u8)} + // validity windows: unbounded = {from: None (0_u8), to: None (0_u8)} let unbounded_window_bytes: &[u8] = &[0_u8; 2]; let expected_borsh_vec: Vec = [ @@ -246,13 +246,11 @@ pub mod tests { #[test] fn encrypted_account_data_constructor() { let npk = NullifierPublicKey::from(&[1; 32]); - let vpk = ViewingPublicKey::from_scalar([2; 32]); + let vpk = ViewingPublicKey::from_seed(&[2_u8; 32], &[3_u8; 32]); let account = Account::default(); - let account_id = nssa_core::account::AccountId::for_regular_private_account(&npk, 0); + let account_id = lee_core::account::AccountId::for_regular_private_account(&npk, 0); let commitment = Commitment::new(&account_id, &account); - let esk = [3; 32]; - let shared_secret = SharedSecretKey::new(esk, &vpk); - let epk = EphemeralPublicKey::from_scalar(esk); + let (shared_secret, epk) = SharedSecretKey::encapsulate_deterministic(&vpk, &[0_u8; 32], 0); let ciphertext = EncryptionScheme::encrypt( &account, &PrivateAccountKind::Regular(0), diff --git a/nssa/src/privacy_preserving_transaction/mod.rs b/lee/state_machine/src/privacy_preserving_transaction/mod.rs similarity index 100% rename from nssa/src/privacy_preserving_transaction/mod.rs rename to lee/state_machine/src/privacy_preserving_transaction/mod.rs diff --git a/nssa/src/privacy_preserving_transaction/transaction.rs b/lee/state_machine/src/privacy_preserving_transaction/transaction.rs similarity index 98% rename from nssa/src/privacy_preserving_transaction/transaction.rs rename to lee/state_machine/src/privacy_preserving_transaction/transaction.rs index 2e46f628..055d65c1 100644 --- a/nssa/src/privacy_preserving_transaction/transaction.rs +++ b/lee/state_machine/src/privacy_preserving_transaction/transaction.rs @@ -1,7 +1,7 @@ use std::collections::HashSet; use borsh::{BorshDeserialize, BorshSerialize}; -use nssa_core::account::AccountId; +use lee_core::account::AccountId; use sha2::{Digest as _, digest::FixedOutput as _}; use super::{message::Message, witness_set::WitnessSet}; diff --git a/nssa/src/privacy_preserving_transaction/witness_set.rs b/lee/state_machine/src/privacy_preserving_transaction/witness_set.rs similarity index 100% rename from nssa/src/privacy_preserving_transaction/witness_set.rs rename to lee/state_machine/src/privacy_preserving_transaction/witness_set.rs diff --git a/nssa/src/program.rs b/lee/state_machine/src/program.rs similarity index 90% rename from nssa/src/program.rs rename to lee/state_machine/src/program.rs index 696c2086..9692a5ee 100644 --- a/nssa/src/program.rs +++ b/lee/state_machine/src/program.rs @@ -1,5 +1,5 @@ use borsh::{BorshDeserialize, BorshSerialize}; -use nssa_core::{ +use lee_core::{ account::AccountWithMetadata, program::{InstructionData, ProgramId, ProgramOutput}, }; @@ -7,11 +7,12 @@ use risc0_zkvm::{ExecutorEnv, ExecutorEnvBuilder, default_executor, serde::to_ve use serde::Serialize; use crate::{ - error::NssaError, + error::LeeError, program_methods::{ AMM_ELF, AMM_ID, ASSOCIATED_TOKEN_ACCOUNT_ELF, ASSOCIATED_TOKEN_ACCOUNT_ID, - AUTHENTICATED_TRANSFER_ELF, AUTHENTICATED_TRANSFER_ID, CLOCK_ELF, CLOCK_ID, FAUCET_ELF, - FAUCET_ID, PINATA_ELF, PINATA_ID, TOKEN_ELF, TOKEN_ID, VAULT_ELF, VAULT_ID, + AUTHENTICATED_TRANSFER_ELF, AUTHENTICATED_TRANSFER_ID, BRIDGE_ELF, BRIDGE_ID, CLOCK_ELF, + CLOCK_ID, FAUCET_ELF, FAUCET_ID, PINATA_ELF, PINATA_ID, TOKEN_ELF, TOKEN_ID, VAULT_ELF, + VAULT_ID, }, }; @@ -26,12 +27,12 @@ pub struct Program { } impl Program { - pub fn new(bytecode: Vec) -> Result { + pub fn new(bytecode: Vec) -> Result { let binary = risc0_binfmt::ProgramBinary::decode(&bytecode) - .map_err(NssaError::InvalidProgramBytecode)?; + .map_err(LeeError::InvalidProgramBytecode)?; let id = binary .compute_image_id() - .map_err(NssaError::InvalidProgramBytecode)? + .map_err(LeeError::InvalidProgramBytecode)? .into(); Ok(Self { elf: bytecode, id }) } @@ -48,8 +49,8 @@ impl Program { pub fn serialize_instruction( instruction: T, - ) -> Result { - to_vec(&instruction).map_err(|e| NssaError::InstructionSerializationError(e.to_string())) + ) -> Result { + to_vec(&instruction).map_err(|e| LeeError::InstructionSerializationError(e.to_string())) } pub(crate) fn execute( @@ -57,7 +58,7 @@ impl Program { caller_program_id: Option, pre_states: &[AccountWithMetadata], instruction_data: &InstructionData, - ) -> Result { + ) -> Result { // Write inputs to the program let mut env_builder = ExecutorEnv::builder(); env_builder.session_limit(Some(MAX_NUM_CYCLES_PUBLIC_EXECUTION)); @@ -74,13 +75,13 @@ impl Program { let executor = default_executor(); let session_info = executor .execute(env, self.elf()) - .map_err(|e| NssaError::ProgramExecutionFailed(e.to_string()))?; + .map_err(|e| LeeError::ProgramExecutionFailed(e.to_string()))?; // Get outputs let program_output = session_info .journal .decode() - .map_err(|e| NssaError::ProgramExecutionFailed(e.to_string()))?; + .map_err(|e| LeeError::ProgramExecutionFailed(e.to_string()))?; Ok(program_output) } @@ -92,20 +93,20 @@ impl Program { pre_states: &[AccountWithMetadata], instruction_data: &[u32], env_builder: &mut ExecutorEnvBuilder, - ) -> Result<(), NssaError> { + ) -> Result<(), LeeError> { env_builder .write(&program_id) - .map_err(|e| NssaError::ProgramWriteInputFailed(e.to_string()))?; + .map_err(|e| LeeError::ProgramWriteInputFailed(e.to_string()))?; env_builder .write(&caller_program_id) - .map_err(|e| NssaError::ProgramWriteInputFailed(e.to_string()))?; + .map_err(|e| LeeError::ProgramWriteInputFailed(e.to_string()))?; let pre_states = pre_states.to_vec(); env_builder .write(&pre_states) - .map_err(|e| NssaError::ProgramWriteInputFailed(e.to_string()))?; + .map_err(|e| LeeError::ProgramWriteInputFailed(e.to_string()))?; env_builder .write(&instruction_data) - .map_err(|e| NssaError::ProgramWriteInputFailed(e.to_string()))?; + .map_err(|e| LeeError::ProgramWriteInputFailed(e.to_string()))?; Ok(()) } @@ -164,6 +165,14 @@ impl Program { elf: FAUCET_ELF.to_vec(), } } + + #[must_use] + pub fn bridge() -> Self { + Self { + id: BRIDGE_ID, + elf: BRIDGE_ELF.to_vec(), + } + } } // TODO: Testnet only. Refactor to prevent compilation on mainnet. @@ -188,15 +197,15 @@ impl Program { #[cfg(test)] mod tests { - use nssa_core::account::{Account, AccountId, AccountWithMetadata}; + use lee_core::account::{Account, AccountId, AccountWithMetadata}; use crate::{ program::Program, program_methods::{ AMM_ELF, AMM_ID, ASSOCIATED_TOKEN_ACCOUNT_ELF, ASSOCIATED_TOKEN_ACCOUNT_ID, - AUTHENTICATED_TRANSFER_ELF, AUTHENTICATED_TRANSFER_ID, CLOCK_ELF, CLOCK_ID, FAUCET_ELF, - FAUCET_ID, PINATA_ELF, PINATA_ID, PINATA_TOKEN_ELF, PINATA_TOKEN_ID, TOKEN_ELF, - TOKEN_ID, VAULT_ELF, VAULT_ID, + AUTHENTICATED_TRANSFER_ELF, AUTHENTICATED_TRANSFER_ID, BRIDGE_ELF, BRIDGE_ID, + CLOCK_ELF, CLOCK_ID, FAUCET_ELF, FAUCET_ID, PINATA_ELF, PINATA_ID, PINATA_TOKEN_ELF, + PINATA_TOKEN_ID, TOKEN_ELF, TOKEN_ID, VAULT_ELF, VAULT_ID, }, }; @@ -529,6 +538,7 @@ mod tests { let token_program = Program::token(); let vault_program = Program::vault(); let faucet_program = Program::faucet(); + let bridge_program = Program::bridge(); let pinata_program = Program::pinata(); assert_eq!(auth_transfer_program.id, AUTHENTICATED_TRANSFER_ID); @@ -539,6 +549,8 @@ mod tests { assert_eq!(vault_program.elf, VAULT_ELF); assert_eq!(faucet_program.id, FAUCET_ID); assert_eq!(faucet_program.elf, FAUCET_ELF); + assert_eq!(bridge_program.id, BRIDGE_ID); + assert_eq!(bridge_program.elf, BRIDGE_ELF); assert_eq!(pinata_program.id, PINATA_ID); assert_eq!(pinata_program.elf, PINATA_ELF); } @@ -551,6 +563,7 @@ mod tests { (ASSOCIATED_TOKEN_ACCOUNT_ELF, ASSOCIATED_TOKEN_ACCOUNT_ID), (CLOCK_ELF, CLOCK_ID), (FAUCET_ELF, FAUCET_ID), + (BRIDGE_ELF, BRIDGE_ID), (PINATA_ELF, PINATA_ID), (PINATA_TOKEN_ELF, PINATA_TOKEN_ID), (TOKEN_ELF, TOKEN_ID), diff --git a/nssa/src/program_deployment_transaction/message.rs b/lee/state_machine/src/program_deployment_transaction/message.rs similarity index 100% rename from nssa/src/program_deployment_transaction/message.rs rename to lee/state_machine/src/program_deployment_transaction/message.rs diff --git a/nssa/src/program_deployment_transaction/mod.rs b/lee/state_machine/src/program_deployment_transaction/mod.rs similarity index 100% rename from nssa/src/program_deployment_transaction/mod.rs rename to lee/state_machine/src/program_deployment_transaction/mod.rs diff --git a/nssa/src/program_deployment_transaction/transaction.rs b/lee/state_machine/src/program_deployment_transaction/transaction.rs similarity index 96% rename from nssa/src/program_deployment_transaction/transaction.rs rename to lee/state_machine/src/program_deployment_transaction/transaction.rs index 3fa775a8..890d6c3e 100644 --- a/nssa/src/program_deployment_transaction/transaction.rs +++ b/lee/state_machine/src/program_deployment_transaction/transaction.rs @@ -1,5 +1,5 @@ use borsh::{BorshDeserialize, BorshSerialize}; -use nssa_core::account::AccountId; +use lee_core::account::AccountId; use sha2::{Digest as _, digest::FixedOutput as _}; use crate::program_deployment_transaction::message::Message; diff --git a/nssa/src/public_transaction/message.rs b/lee/state_machine/src/public_transaction/message.rs similarity index 96% rename from nssa/src/public_transaction/message.rs rename to lee/state_machine/src/public_transaction/message.rs index 3ab7d74c..feafc539 100644 --- a/nssa/src/public_transaction/message.rs +++ b/lee/state_machine/src/public_transaction/message.rs @@ -1,12 +1,12 @@ use borsh::{BorshDeserialize, BorshSerialize}; -use nssa_core::{ +use lee_core::{ account::Nonce, program::{InstructionData, ProgramId}, }; use serde::Serialize; use sha2::{Digest as _, Sha256}; -use crate::{AccountId, error::NssaError, program::Program}; +use crate::{AccountId, error::LeeError, program::Program}; const PREFIX: &[u8; 32] = b"/LEE/v0.3/Message/Public/\x00\x00\x00\x00\x00\x00\x00"; @@ -41,7 +41,7 @@ impl Message { account_ids: Vec, nonces: Vec, instruction: T, - ) -> Result { + ) -> Result { let instruction_data = Program::serialize_instruction(instruction)?; Ok(Self { @@ -84,7 +84,7 @@ impl Message { #[cfg(test)] mod tests { - use nssa_core::account::{AccountId, Nonce}; + use lee_core::account::{AccountId, Nonce}; use sha2::{Digest as _, Sha256}; use super::{Message, PREFIX}; diff --git a/nssa/src/public_transaction/mod.rs b/lee/state_machine/src/public_transaction/mod.rs similarity index 100% rename from nssa/src/public_transaction/mod.rs rename to lee/state_machine/src/public_transaction/mod.rs diff --git a/nssa/src/public_transaction/transaction.rs b/lee/state_machine/src/public_transaction/transaction.rs similarity index 95% rename from nssa/src/public_transaction/transaction.rs rename to lee/state_machine/src/public_transaction/transaction.rs index 8ab79535..1d1fee0d 100644 --- a/nssa/src/public_transaction/transaction.rs +++ b/lee/state_machine/src/public_transaction/transaction.rs @@ -1,7 +1,7 @@ use std::collections::HashSet; use borsh::{BorshDeserialize, BorshSerialize}; -use nssa_core::account::AccountId; +use lee_core::account::AccountId; use sha2::{Digest as _, digest::FixedOutput as _}; use crate::public_transaction::{Message, WitnessSet}; @@ -65,7 +65,7 @@ pub mod tests { use crate::{ AccountId, PrivateKey, PublicKey, PublicTransaction, Signature, V03State, - error::NssaError, + error::LeeError, program::Program, public_transaction::{Message, WitnessSet}, validated_state_diff::ValidatedStateDiff, @@ -178,7 +178,7 @@ pub mod tests { let witness_set = WitnessSet::for_message(&message, &[&key1, &key1]); let tx = PublicTransaction::new(message, witness_set); let result = ValidatedStateDiff::from_public_transaction(&tx, &state, 1, 0); - assert!(matches!(result, Err(NssaError::InvalidInput(_)))); + assert!(matches!(result, Err(LeeError::InvalidInput(_)))); } #[test] @@ -198,7 +198,7 @@ pub mod tests { let witness_set = WitnessSet::for_message(&message, &[&key1, &key2]); let tx = PublicTransaction::new(message, witness_set); let result = ValidatedStateDiff::from_public_transaction(&tx, &state, 1, 0); - assert!(matches!(result, Err(NssaError::InvalidInput(_)))); + assert!(matches!(result, Err(LeeError::InvalidInput(_)))); } #[test] @@ -219,7 +219,7 @@ pub mod tests { witness_set.signatures_and_public_keys[0].0 = Signature::new_for_tests([1; 64]); let tx = PublicTransaction::new(message, witness_set); let result = ValidatedStateDiff::from_public_transaction(&tx, &state, 1, 0); - assert!(matches!(result, Err(NssaError::InvalidInput(_)))); + assert!(matches!(result, Err(LeeError::InvalidInput(_)))); } #[test] @@ -239,7 +239,7 @@ pub mod tests { let witness_set = WitnessSet::for_message(&message, &[&key1, &key2]); let tx = PublicTransaction::new(message, witness_set); let result = ValidatedStateDiff::from_public_transaction(&tx, &state, 1, 0); - assert!(matches!(result, Err(NssaError::InvalidInput(_)))); + assert!(matches!(result, Err(LeeError::InvalidInput(_)))); } #[test] @@ -255,6 +255,6 @@ pub mod tests { let witness_set = WitnessSet::for_message(&message, &[&key1, &key2]); let tx = PublicTransaction::new(message, witness_set); let result = ValidatedStateDiff::from_public_transaction(&tx, &state, 1, 0); - assert!(matches!(result, Err(NssaError::InvalidInput(_)))); + assert!(matches!(result, Err(LeeError::InvalidInput(_)))); } } diff --git a/nssa/src/public_transaction/witness_set.rs b/lee/state_machine/src/public_transaction/witness_set.rs similarity index 100% rename from nssa/src/public_transaction/witness_set.rs rename to lee/state_machine/src/public_transaction/witness_set.rs diff --git a/nssa/src/signature/bip340_test_vectors.rs b/lee/state_machine/src/signature/bip340_test_vectors.rs similarity index 100% rename from nssa/src/signature/bip340_test_vectors.rs rename to lee/state_machine/src/signature/bip340_test_vectors.rs diff --git a/nssa/src/signature/mod.rs b/lee/state_machine/src/signature/mod.rs similarity index 100% rename from nssa/src/signature/mod.rs rename to lee/state_machine/src/signature/mod.rs diff --git a/nssa/src/signature/private_key.rs b/lee/state_machine/src/signature/private_key.rs similarity index 86% rename from nssa/src/signature/private_key.rs rename to lee/state_machine/src/signature/private_key.rs index 1bfecf80..29f3cd3c 100644 --- a/nssa/src/signature/private_key.rs +++ b/lee/state_machine/src/signature/private_key.rs @@ -3,7 +3,7 @@ use std::str::FromStr; use rand::{Rng as _, rngs::OsRng}; use serde_with::{DeserializeFromStr, SerializeDisplay}; -use crate::error::NssaError; +use crate::error::LeeError; // TODO: Remove Debug, Clone, Serialize, Deserialize, PartialEq and Eq for security reasons // TODO: Implement Zeroize @@ -23,11 +23,11 @@ impl std::fmt::Display for PrivateKey { } impl FromStr for PrivateKey { - type Err = NssaError; + type Err = LeeError; fn from_str(s: &str) -> Result { let mut bytes = [0_u8; 32]; - hex::decode_to_slice(s, &mut bytes).map_err(|_err| NssaError::InvalidPrivateKey)?; + hex::decode_to_slice(s, &mut bytes).map_err(|_err| LeeError::InvalidPrivateKey)?; Self::try_new(bytes) } } @@ -48,11 +48,11 @@ impl PrivateKey { k256::SecretKey::from_bytes(&value.into()).is_ok() } - pub fn try_new(value: [u8; 32]) -> Result { + pub fn try_new(value: [u8; 32]) -> Result { if Self::is_valid_key(value) { Ok(Self(value)) } else { - Err(NssaError::InvalidPrivateKey) + Err(LeeError::InvalidPrivateKey) } } diff --git a/nssa/src/signature/public_key.rs b/lee/state_machine/src/signature/public_key.rs similarity index 89% rename from nssa/src/signature/public_key.rs rename to lee/state_machine/src/signature/public_key.rs index ebec6b62..6aa6e982 100644 --- a/nssa/src/signature/public_key.rs +++ b/lee/state_machine/src/signature/public_key.rs @@ -2,11 +2,11 @@ use std::str::FromStr; use borsh::{BorshDeserialize, BorshSerialize}; use k256::elliptic_curve::sec1::ToEncodedPoint as _; -use nssa_core::account::AccountId; +use lee_core::account::AccountId; use serde_with::{DeserializeFromStr, SerializeDisplay}; use sha2::{Digest as _, Sha256}; -use crate::{PrivateKey, error::NssaError}; +use crate::{PrivateKey, error::LeeError}; #[derive(Clone, PartialEq, Eq, BorshSerialize, SerializeDisplay, DeserializeFromStr)] pub struct PublicKey([u8; 32]); @@ -24,11 +24,11 @@ impl std::fmt::Display for PublicKey { } impl FromStr for PublicKey { - type Err = NssaError; + type Err = LeeError; fn from_str(s: &str) -> Result { let mut bytes = [0_u8; 32]; - hex::decode_to_slice(s, &mut bytes).map_err(NssaError::InvalidHexPublicKey)?; + hex::decode_to_slice(s, &mut bytes).map_err(LeeError::InvalidHexPublicKey)?; Self::try_new(bytes) } } @@ -59,10 +59,10 @@ impl PublicKey { Self(value) } - pub fn try_new(value: [u8; 32]) -> Result { + pub fn try_new(value: [u8; 32]) -> Result { // Check point is a valid x-only public key let _ = - k256::schnorr::VerifyingKey::from_bytes(&value).map_err(NssaError::InvalidPublicKey)?; + k256::schnorr::VerifyingKey::from_bytes(&value).map_err(LeeError::InvalidPublicKey)?; Ok(Self(value)) } @@ -87,7 +87,7 @@ impl From<&PublicKey> for AccountId { #[cfg(test)] mod test { - use crate::{PublicKey, error::NssaError, signature::bip340_test_vectors}; + use crate::{PublicKey, error::LeeError, signature::bip340_test_vectors}; #[test] fn try_new_invalid_public_key_from_bip340_test_vectors_5() { @@ -98,7 +98,7 @@ mod test { let result = PublicKey::try_new(value_invalid_key); - assert!(matches!(result, Err(NssaError::InvalidPublicKey(_)))); + assert!(matches!(result, Err(LeeError::InvalidPublicKey(_)))); } #[test] @@ -110,7 +110,7 @@ mod test { let result = PublicKey::try_new(value_invalid_key); - assert!(matches!(result, Err(NssaError::InvalidPublicKey(_)))); + assert!(matches!(result, Err(LeeError::InvalidPublicKey(_)))); } #[test] diff --git a/nssa/src/state.rs b/lee/state_machine/src/state.rs similarity index 93% rename from nssa/src/state.rs rename to lee/state_machine/src/state.rs index 0f38f9f3..4b74cf55 100644 --- a/nssa/src/state.rs +++ b/lee/state_machine/src/state.rs @@ -6,7 +6,7 @@ pub use clock_core::{ CLOCK_01_PROGRAM_ACCOUNT_ID, CLOCK_10_PROGRAM_ACCOUNT_ID, CLOCK_50_PROGRAM_ACCOUNT_ID, CLOCK_PROGRAM_ACCOUNT_IDS, }; -use nssa_core::{ +use lee_core::{ BlockId, Commitment, CommitmentSetDigest, DUMMY_COMMITMENT, MembershipProof, Nullifier, Timestamp, account::{Account, AccountId, Nonce}, @@ -14,7 +14,7 @@ use nssa_core::{ }; use crate::{ - error::NssaError, + error::LeeError, merkle_tree::MerkleTree, privacy_preserving_transaction::PrivacyPreservingTransaction, program::Program, @@ -126,8 +126,11 @@ impl Default for V03State { fn default() -> Self { let faucet_account_id = system_faucet_account_id(); let faucet_account = system_faucet_account(); + let bridge_account_id = system_bridge_account_id(); + let bridge_account = system_bridge_account(); let mut public_state = HashMap::new(); public_state.insert(faucet_account_id, faucet_account); + public_state.insert(bridge_account_id, bridge_account); Self { public_state, @@ -147,9 +150,10 @@ impl V03State { pub fn new_with_genesis_accounts( initial_data: &[(AccountId, u128)], initial_private_accounts: Vec<(Commitment, Nullifier)>, - genesis_timestamp: nssa_core::Timestamp, + genesis_timestamp: lee_core::Timestamp, ) -> Self { let faucet_account_id = system_faucet_account_id(); + let bridge_account_id = system_bridge_account_id(); let authenticated_transfer_program = Program::authenticated_transfer_program(); let mut public_state: HashMap<_, _> = initial_data .iter() @@ -164,7 +168,9 @@ impl V03State { }) .collect(); let faucet_account = system_faucet_account(); + let bridge_account = system_bridge_account(); public_state.insert(faucet_account_id, faucet_account); + public_state.insert(bridge_account_id, bridge_account); let mut commitment_set = CommitmentSet::with_capacity(32); commitment_set.extend(&[DUMMY_COMMITMENT]); @@ -190,11 +196,12 @@ impl V03State { this.insert_program(Program::ata()); this.insert_program(Program::vault()); this.insert_program(Program::faucet()); + this.insert_program(Program::bridge()); this } - fn insert_clock_accounts(&mut self, genesis_timestamp: nssa_core::Timestamp) { + fn insert_clock_accounts(&mut self, genesis_timestamp: lee_core::Timestamp) { let data = ClockAccountData { block_id: 0, timestamp: genesis_timestamp, @@ -252,7 +259,7 @@ impl V03State { tx: &PublicTransaction, block_id: BlockId, timestamp: Timestamp, - ) -> Result<(), NssaError> { + ) -> Result<(), LeeError> { let diff = ValidatedStateDiff::from_public_transaction(tx, self, block_id, timestamp)?; self.apply_state_diff(diff); Ok(()) @@ -263,7 +270,7 @@ impl V03State { tx: &PrivacyPreservingTransaction, block_id: BlockId, timestamp: Timestamp, - ) -> Result<(), NssaError> { + ) -> Result<(), LeeError> { let diff = ValidatedStateDiff::from_privacy_preserving_transaction(tx, self, block_id, timestamp)?; self.apply_state_diff(diff); @@ -273,7 +280,7 @@ impl V03State { pub fn transition_from_program_deployment_transaction( &mut self, tx: &ProgramDeploymentTransaction, - ) -> Result<(), NssaError> { + ) -> Result<(), LeeError> { let diff = ValidatedStateDiff::from_program_deployment_transaction(tx, self)?; self.apply_state_diff(diff); Ok(()) @@ -308,12 +315,10 @@ impl V03State { pub(crate) fn check_commitments_are_new( &self, new_commitments: &[Commitment], - ) -> Result<(), NssaError> { + ) -> Result<(), LeeError> { for commitment in new_commitments { if self.private_state.0.contains(commitment) { - return Err(NssaError::InvalidInput( - "Commitment already seen".to_owned(), - )); + return Err(LeeError::InvalidInput("Commitment already seen".to_owned())); } } Ok(()) @@ -322,13 +327,13 @@ impl V03State { pub(crate) fn check_nullifiers_are_valid( &self, new_nullifiers: &[(Nullifier, CommitmentSetDigest)], - ) -> Result<(), NssaError> { + ) -> Result<(), LeeError> { for (nullifier, digest) in new_nullifiers { if self.private_state.1.contains(nullifier) { - return Err(NssaError::InvalidInput("Nullifier already seen".to_owned())); + return Err(LeeError::InvalidInput("Nullifier already seen".to_owned())); } if !self.private_state.0.root_history.contains(digest) { - return Err(NssaError::InvalidInput( + return Err(LeeError::InvalidInput( "Unrecognized commitment set digest".to_owned(), )); } @@ -384,11 +389,23 @@ fn system_faucet_account() -> Account { } } +fn system_bridge_account() -> Account { + Account { + program_owner: Program::authenticated_transfer_program().id(), + ..Account::default() + } +} + #[must_use] pub fn system_faucet_account_id() -> AccountId { faucet_core::compute_faucet_account_id(Program::faucet().id()) } +#[must_use] +pub fn system_bridge_account_id() -> AccountId { + bridge_core::compute_bridge_account_id(Program::bridge().id()) +} + #[cfg(test)] pub mod tests { #![expect( @@ -400,11 +417,11 @@ pub mod tests { use std::collections::HashMap; use authenticated_transfer_core::Instruction as AuthTransferInstruction; - use nssa_core::{ + use lee_core::{ BlockId, Commitment, InputAccountIdentity, Nullifier, NullifierPublicKey, NullifierSecretKey, SharedSecretKey, Timestamp, account::{Account, AccountId, AccountWithMetadata, Nonce, data::Data}, - encryption::{EphemeralPublicKey, Scalar, ViewingPublicKey}, + encryption::{EphemeralPublicKey, ViewingPublicKey}, program::{ BlockValidityWindow, ExecutionValidationError, PdaSeed, ProgramId, TimestampValidityWindow, WrappedBalanceSum, @@ -413,7 +430,7 @@ pub mod tests { use crate::{ PublicKey, PublicTransaction, V03State, - error::{InvalidProgramBehaviorError, NssaError}, + error::{InvalidProgramBehaviorError, LeeError}, execute_and_prove, privacy_preserving_transaction::{ PrivacyPreservingTransaction, @@ -426,9 +443,10 @@ pub mod tests { signature::PrivateKey, state::{ CLOCK_01_PROGRAM_ACCOUNT_ID, CLOCK_10_PROGRAM_ACCOUNT_ID, CLOCK_50_PROGRAM_ACCOUNT_ID, - CLOCK_PROGRAM_ACCOUNT_IDS, MAX_NUMBER_CHAINED_CALLS, system_faucet_account, + CLOCK_PROGRAM_ACCOUNT_IDS, MAX_NUMBER_CHAINED_CALLS, system_bridge_account, + system_faucet_account, }, - system_faucet_account_id, + system_bridge_account_id, system_faucet_account_id, }; impl V03State { @@ -518,7 +536,8 @@ pub mod tests { pub struct TestPrivateKeys { pub nsk: NullifierSecretKey, - pub vsk: Scalar, + pub d: [u8; 32], + pub z: [u8; 32], } impl TestPrivateKeys { @@ -527,7 +546,7 @@ pub mod tests { } pub fn vpk(&self) -> ViewingPublicKey { - ViewingPublicKey::from_scalar(self.vsk) + ViewingPublicKey::from_seed(&self.d, &self.z) } } @@ -622,6 +641,7 @@ pub mod tests { }, ); this.insert(system_faucet_account_id(), system_faucet_account()); + this.insert(system_bridge_account_id(), system_bridge_account()); for account_id in CLOCK_PROGRAM_ACCOUNT_IDS { this.insert( account_id, @@ -646,6 +666,7 @@ pub mod tests { this.insert(Program::ata().id(), Program::ata()); this.insert(Program::vault().id(), Program::vault()); this.insert(Program::faucet().id(), Program::faucet()); + this.insert(Program::bridge().id(), Program::bridge()); this }; @@ -767,7 +788,7 @@ pub mod tests { let tx = transfer_transaction(from, &from_key, 0, to, &to_key, 0, balance_to_move); let result = state.transition_from_public_transaction(&tx, 1, 0); - assert!(matches!(result, Err(NssaError::ProgramExecutionFailed(_)))); + assert!(matches!(result, Err(LeeError::ProgramExecutionFailed(_)))); assert_eq!(state.get_account_by_id(from).balance, 100); assert_eq!(state.get_account_by_id(to).balance, 0); assert_eq!(state.get_account_by_id(from).nonce, Nonce(0)); @@ -840,7 +861,7 @@ pub mod tests { assert_eq!(state.get_account_by_id(account_id3).nonce, Nonce(1)); } - fn clock_transaction(timestamp: nssa_core::Timestamp) -> PublicTransaction { + fn clock_transaction(timestamp: lee_core::Timestamp) -> PublicTransaction { let message = public_transaction::Message::try_new( Program::clock().id(), CLOCK_PROGRAM_ACCOUNT_IDS.to_vec(), @@ -854,7 +875,7 @@ pub mod tests { ) } - fn clock_account_data(state: &V03State, account_id: AccountId) -> (u64, nssa_core::Timestamp) { + fn clock_account_data(state: &V03State, account_id: AccountId) -> (u64, lee_core::Timestamp) { let data = state.get_account_by_id(account_id).data.into_inner(); let parsed = clock_core::ClockAccountData::from_bytes(&data); (parsed.block_id, parsed.timestamp) @@ -1000,7 +1021,7 @@ pub mod tests { assert!(matches!( result, - Err(NssaError::InvalidProgramBehavior( + Err(LeeError::InvalidProgramBehavior( InvalidProgramBehaviorError::ExecutionValidationFailed( ExecutionValidationError::ModifiedNonce { account_id: err_account_id } ) @@ -1024,7 +1045,7 @@ pub mod tests { assert!(matches!( result, - Err(NssaError::InvalidProgramBehavior( + Err(LeeError::InvalidProgramBehavior( InvalidProgramBehaviorError::ExecutionValidationFailed( ExecutionValidationError::MismatchedPreStatePostStateLength { pre_state_length, @@ -1051,7 +1072,7 @@ pub mod tests { assert!(matches!( result, - Err(NssaError::InvalidProgramBehavior( + Err(LeeError::InvalidProgramBehavior( InvalidProgramBehaviorError::ExecutionValidationFailed( ExecutionValidationError::MismatchedPreStatePostStateLength { pre_state_length, @@ -1085,7 +1106,7 @@ pub mod tests { assert!(matches!( result, - Err(NssaError::InvalidProgramBehavior(InvalidProgramBehaviorError::ExecutionValidationFailed( + Err(LeeError::InvalidProgramBehavior(InvalidProgramBehaviorError::ExecutionValidationFailed( ExecutionValidationError::ModifiedProgramOwner { account_id: err_account_id } ))) if err_account_id == account_id )); @@ -1114,7 +1135,7 @@ pub mod tests { assert!(matches!( result, - Err(NssaError::InvalidProgramBehavior(InvalidProgramBehaviorError::ExecutionValidationFailed( + Err(LeeError::InvalidProgramBehavior(InvalidProgramBehaviorError::ExecutionValidationFailed( ExecutionValidationError::ModifiedProgramOwner { account_id: err_account_id } ))) if err_account_id == account_id )); @@ -1143,7 +1164,7 @@ pub mod tests { assert!(matches!( result, - Err(NssaError::InvalidProgramBehavior(InvalidProgramBehaviorError::ExecutionValidationFailed( + Err(LeeError::InvalidProgramBehavior(InvalidProgramBehaviorError::ExecutionValidationFailed( ExecutionValidationError::ModifiedProgramOwner { account_id: err_account_id } ))) if err_account_id == account_id )); @@ -1172,7 +1193,7 @@ pub mod tests { assert!(matches!( result, - Err(NssaError::InvalidProgramBehavior(InvalidProgramBehaviorError::ExecutionValidationFailed( + Err(LeeError::InvalidProgramBehavior(InvalidProgramBehaviorError::ExecutionValidationFailed( ExecutionValidationError::ModifiedProgramOwner { account_id: err_account_id } ))) if err_account_id == account_id )); @@ -1205,7 +1226,7 @@ pub mod tests { assert!(matches!( result, - Err(NssaError::InvalidProgramBehavior(InvalidProgramBehaviorError::ExecutionValidationFailed( + Err(LeeError::InvalidProgramBehavior(InvalidProgramBehaviorError::ExecutionValidationFailed( ExecutionValidationError::UnauthorizedBalanceDecrease { account_id: err_account_id, owner_program_id, executing_program_id } ))) if err_account_id == sender_account_id && owner_program_id != program_id && executing_program_id == program_id )); @@ -1235,7 +1256,7 @@ pub mod tests { assert!(matches!( result, - Err(NssaError::InvalidProgramBehavior(InvalidProgramBehaviorError::ExecutionValidationFailed( + Err(LeeError::InvalidProgramBehavior(InvalidProgramBehaviorError::ExecutionValidationFailed( ExecutionValidationError::UnauthorizedDataModification { account_id: err_account_id, executing_program_id } ))) if err_account_id == account_id && executing_program_id == program_id )); @@ -1258,7 +1279,7 @@ pub mod tests { assert!(matches!( result, - Err(NssaError::InvalidProgramBehavior(InvalidProgramBehaviorError::ExecutionValidationFailed( + Err(LeeError::InvalidProgramBehavior(InvalidProgramBehaviorError::ExecutionValidationFailed( ExecutionValidationError::MismatchedTotalBalance { total_balance_pre_states, total_balance_post_states } ))) if total_balance_pre_states == 0.into() && total_balance_post_states == 1.into() )); @@ -1292,7 +1313,7 @@ pub mod tests { assert!(matches!( result, - Err(NssaError::InvalidProgramBehavior(InvalidProgramBehaviorError::ExecutionValidationFailed( + Err(LeeError::InvalidProgramBehavior(InvalidProgramBehaviorError::ExecutionValidationFailed( ExecutionValidationError::MismatchedTotalBalance { total_balance_pre_states, total_balance_post_states } ))) if total_balance_pre_states == 100.into() && total_balance_post_states == 99.into() )); @@ -1313,14 +1334,16 @@ pub mod tests { pub fn test_private_account_keys_1() -> TestPrivateKeys { TestPrivateKeys { nsk: [13; 32], - vsk: [31; 32], + d: [31; 32], + z: [32; 32], } } pub fn test_private_account_keys_2() -> TestPrivateKeys { TestPrivateKeys { nsk: [38; 32], - vsk: [83; 32], + d: [83; 32], + z: [84; 32], } } @@ -1341,9 +1364,8 @@ pub mod tests { let recipient = AccountWithMetadata::new(Account::default(), false, (&recipient_keys.npk(), 0)); - let esk = [3; 32]; - let shared_secret = SharedSecretKey::new(esk, &recipient_keys.vpk()); - let epk = EphemeralPublicKey::from_scalar(esk); + let (shared_secret, epk) = + SharedSecretKey::encapsulate_deterministic(&recipient_keys.vpk(), &[0_u8; 32], 0); let (output, proof) = circuit::execute_and_prove( vec![sender, recipient], @@ -1393,13 +1415,11 @@ pub mod tests { let recipient_pre = AccountWithMetadata::new(Account::default(), false, (&recipient_keys.npk(), 0)); - let esk_1 = [3; 32]; - let shared_secret_1 = SharedSecretKey::new(esk_1, &sender_keys.vpk()); - let epk_1 = EphemeralPublicKey::from_scalar(esk_1); + let (shared_secret_1, epk_1) = + SharedSecretKey::encapsulate_deterministic(&sender_keys.vpk(), &[0_u8; 32], 0); - let esk_2 = [3; 32]; - let shared_secret_2 = SharedSecretKey::new(esk_2, &recipient_keys.vpk()); - let epk_2 = EphemeralPublicKey::from_scalar(esk_2); + let (shared_secret_2, epk_2) = + SharedSecretKey::encapsulate_deterministic(&recipient_keys.vpk(), &[0_u8; 32], 1); let (output, proof) = circuit::execute_and_prove( vec![sender_pre, recipient_pre], @@ -1463,9 +1483,8 @@ pub mod tests { *recipient_account_id, ); - let esk = [3; 32]; - let shared_secret = SharedSecretKey::new(esk, &sender_keys.vpk()); - let epk = EphemeralPublicKey::from_scalar(esk); + let (shared_secret, epk) = + SharedSecretKey::encapsulate_deterministic(&sender_keys.vpk(), &[0_u8; 32], 0); let (output, proof) = circuit::execute_and_prove( vec![sender_pre, recipient_pre], @@ -1701,7 +1720,7 @@ pub mod tests { &program.into(), ); - assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + assert!(matches!(result, Err(LeeError::CircuitProvingError(_)))); } #[test] @@ -1724,7 +1743,7 @@ pub mod tests { &program.into(), ); - assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + assert!(matches!(result, Err(LeeError::CircuitProvingError(_)))); } #[test] @@ -1747,7 +1766,7 @@ pub mod tests { &program.into(), ); - assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + assert!(matches!(result, Err(LeeError::CircuitProvingError(_)))); } #[test] @@ -1770,7 +1789,7 @@ pub mod tests { &program.into(), ); - assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + assert!(matches!(result, Err(LeeError::CircuitProvingError(_)))); } #[test] @@ -1789,7 +1808,7 @@ pub mod tests { let large_data: Vec = vec![ 0; - usize::try_from(nssa_core::account::data::DATA_MAX_LENGTH.as_u64()) + usize::try_from(lee_core::account::data::DATA_MAX_LENGTH.as_u64()) .expect("DATA_MAX_LENGTH fits in usize") + 1 ]; @@ -1801,7 +1820,7 @@ pub mod tests { &program.into(), ); - assert!(matches!(result, Err(NssaError::ProgramProveFailed(_)))); + assert!(matches!(result, Err(LeeError::ProgramProveFailed(_)))); } #[test] @@ -1824,7 +1843,7 @@ pub mod tests { &program.into(), ); - assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + assert!(matches!(result, Err(LeeError::CircuitProvingError(_)))); } #[test] @@ -1856,7 +1875,7 @@ pub mod tests { &program.into(), ); - assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + assert!(matches!(result, Err(LeeError::CircuitProvingError(_)))); } #[test] @@ -1879,7 +1898,7 @@ pub mod tests { &program.into(), ); - assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + assert!(matches!(result, Err(LeeError::CircuitProvingError(_)))); } #[test] @@ -1911,7 +1930,7 @@ pub mod tests { &program.into(), ); - assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + assert!(matches!(result, Err(LeeError::CircuitProvingError(_)))); } #[test] @@ -1944,7 +1963,7 @@ pub mod tests { &program.into(), ); - assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + assert!(matches!(result, Err(LeeError::CircuitProvingError(_)))); } #[test] @@ -1973,21 +1992,31 @@ pub mod tests { Program::serialize_instruction(10_u128).unwrap(), vec![ InputAccountIdentity::PrivateAuthorizedUpdate { - ssk: SharedSecretKey::new([55; 32], &sender_keys.vpk()), + ssk: SharedSecretKey::encapsulate_deterministic( + &sender_keys.vpk(), + &[0_u8; 32], + 0, + ) + .0, nsk: recipient_keys.nsk, membership_proof: (0, vec![]), identifier: 0, }, InputAccountIdentity::PrivateUnauthorized { npk: recipient_keys.npk(), - ssk: SharedSecretKey::new([56; 32], &recipient_keys.vpk()), + ssk: SharedSecretKey::encapsulate_deterministic( + &recipient_keys.vpk(), + &[0_u8; 32], + 0, + ) + .0, identifier: 0, }, ], &program.into(), ); - assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + assert!(matches!(result, Err(LeeError::CircuitProvingError(_)))); } #[test] @@ -2019,21 +2048,31 @@ pub mod tests { Program::serialize_instruction(10_u128).unwrap(), vec![ InputAccountIdentity::PrivateAuthorizedUpdate { - ssk: SharedSecretKey::new([55; 32], &sender_keys.vpk()), + ssk: SharedSecretKey::encapsulate_deterministic( + &sender_keys.vpk(), + &[0_u8; 32], + 0, + ) + .0, nsk: sender_keys.nsk, membership_proof: (0, vec![]), identifier: 0, }, InputAccountIdentity::PrivateUnauthorized { npk: recipient_keys.npk(), - ssk: SharedSecretKey::new([56; 32], &recipient_keys.vpk()), + ssk: SharedSecretKey::encapsulate_deterministic( + &recipient_keys.vpk(), + &[0_u8; 32], + 0, + ) + .0, identifier: 0, }, ], &program.into(), ); - assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + assert!(matches!(result, Err(LeeError::CircuitProvingError(_)))); } #[test] @@ -2065,21 +2104,31 @@ pub mod tests { Program::serialize_instruction(10_u128).unwrap(), vec![ InputAccountIdentity::PrivateAuthorizedUpdate { - ssk: SharedSecretKey::new([55; 32], &sender_keys.vpk()), + ssk: SharedSecretKey::encapsulate_deterministic( + &sender_keys.vpk(), + &[0_u8; 32], + 0, + ) + .0, nsk: sender_keys.nsk, membership_proof: (0, vec![]), identifier: 0, }, InputAccountIdentity::PrivateUnauthorized { npk: recipient_keys.npk(), - ssk: SharedSecretKey::new([56; 32], &recipient_keys.vpk()), + ssk: SharedSecretKey::encapsulate_deterministic( + &recipient_keys.vpk(), + &[0_u8; 32], + 0, + ) + .0, identifier: 0, }, ], &program.into(), ); - assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + assert!(matches!(result, Err(LeeError::CircuitProvingError(_)))); } #[test] @@ -2111,21 +2160,31 @@ pub mod tests { Program::serialize_instruction(10_u128).unwrap(), vec![ InputAccountIdentity::PrivateAuthorizedUpdate { - ssk: SharedSecretKey::new([55; 32], &sender_keys.vpk()), + ssk: SharedSecretKey::encapsulate_deterministic( + &sender_keys.vpk(), + &[0_u8; 32], + 0, + ) + .0, nsk: sender_keys.nsk, membership_proof: (0, vec![]), identifier: 0, }, InputAccountIdentity::PrivateUnauthorized { npk: recipient_keys.npk(), - ssk: SharedSecretKey::new([56; 32], &recipient_keys.vpk()), + ssk: SharedSecretKey::encapsulate_deterministic( + &recipient_keys.vpk(), + &[0_u8; 32], + 0, + ) + .0, identifier: 0, }, ], &program.into(), ); - assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + assert!(matches!(result, Err(LeeError::CircuitProvingError(_)))); } #[test] @@ -2157,21 +2216,31 @@ pub mod tests { Program::serialize_instruction(10_u128).unwrap(), vec![ InputAccountIdentity::PrivateAuthorizedUpdate { - ssk: SharedSecretKey::new([55; 32], &sender_keys.vpk()), + ssk: SharedSecretKey::encapsulate_deterministic( + &sender_keys.vpk(), + &[0_u8; 32], + 0, + ) + .0, nsk: sender_keys.nsk, membership_proof: (0, vec![]), identifier: 0, }, InputAccountIdentity::PrivateUnauthorized { npk: recipient_keys.npk(), - ssk: SharedSecretKey::new([56; 32], &recipient_keys.vpk()), + ssk: SharedSecretKey::encapsulate_deterministic( + &recipient_keys.vpk(), + &[0_u8; 32], + 0, + ) + .0, identifier: 0, }, ], &program.into(), ); - assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + assert!(matches!(result, Err(LeeError::CircuitProvingError(_)))); } #[test] @@ -2201,21 +2270,31 @@ pub mod tests { Program::serialize_instruction(10_u128).unwrap(), vec![ InputAccountIdentity::PrivateAuthorizedUpdate { - ssk: SharedSecretKey::new([55; 32], &sender_keys.vpk()), + ssk: SharedSecretKey::encapsulate_deterministic( + &sender_keys.vpk(), + &[0_u8; 32], + 0, + ) + .0, nsk: sender_keys.nsk, membership_proof: (0, vec![]), identifier: 0, }, InputAccountIdentity::PrivateUnauthorized { npk: recipient_keys.npk(), - ssk: SharedSecretKey::new([56; 32], &recipient_keys.vpk()), + ssk: SharedSecretKey::encapsulate_deterministic( + &recipient_keys.vpk(), + &[0_u8; 32], + 0, + ) + .0, identifier: 0, }, ], &program.into(), ); - assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + assert!(matches!(result, Err(LeeError::CircuitProvingError(_)))); } /// A private PDA account that no program claims via `Claim::Pda` and no caller authorizes via @@ -2227,7 +2306,8 @@ pub mod tests { let program = Program::simple_balance_transfer(); let keys = test_private_account_keys_1(); let npk = keys.npk(); - let shared_secret = SharedSecretKey::new([55; 32], &keys.vpk()); + let shared_secret = + SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0; let public_account_1 = AccountWithMetadata::new( Account { program_owner: program.id(), @@ -2255,7 +2335,7 @@ pub mod tests { &program.into(), ); - assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + assert!(matches!(result, Err(LeeError::CircuitProvingError(_)))); } /// Happy path: a program claims a new private PDA via `Claim::Pda(seed)`. The circuit @@ -2269,7 +2349,8 @@ pub mod tests { let keys = test_private_account_keys_1(); let npk = keys.npk(); let seed = PdaSeed::new([42; 32]); - let shared_secret = SharedSecretKey::new([55; 32], &keys.vpk()); + let shared_secret = + SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0; let account_id = AccountId::for_private_pda(&program.id(), &seed, &npk, u128::MAX); let pre_state = AccountWithMetadata::new(Account::default(), false, account_id); @@ -2306,7 +2387,8 @@ pub mod tests { let npk_a = keys_a.npk(); let npk_b = keys_b.npk(); let seed = PdaSeed::new([42; 32]); - let shared_secret = SharedSecretKey::new([55; 32], &keys_b.vpk()); + let shared_secret = + SharedSecretKey::encapsulate_deterministic(&keys_b.vpk(), &[0_u8; 32], 0).0; // `account_id` is derived from `npk_a`, but `npk_b` is supplied for this pre_state. // `AccountId::for_private_pda(program, seed, npk_b) != account_id`, so the claim check in @@ -2326,7 +2408,7 @@ pub mod tests { &program.into(), ); - assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + assert!(matches!(result, Err(LeeError::CircuitProvingError(_)))); } /// Happy path for the caller-seeds authorization of a private PDA. The delegator claims a @@ -2341,7 +2423,8 @@ pub mod tests { let keys = test_private_account_keys_1(); let npk = keys.npk(); let seed = PdaSeed::new([77; 32]); - let shared_secret = SharedSecretKey::new([55; 32], &keys.vpk()); + let shared_secret = + SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0; let account_id = AccountId::for_private_pda(&delegator.id(), &seed, &npk, u128::MAX); let pre_state = AccountWithMetadata::new(Account::default(), false, account_id); @@ -2380,7 +2463,8 @@ pub mod tests { let npk = keys.npk(); let claim_seed = PdaSeed::new([77; 32]); let wrong_delegated_seed = PdaSeed::new([88; 32]); - let shared_secret = SharedSecretKey::new([55; 32], &keys.vpk()); + let shared_secret = + SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0; let account_id = AccountId::for_private_pda(&delegator.id(), &claim_seed, &npk, u128::MAX); let pre_state = AccountWithMetadata::new(Account::default(), false, account_id); @@ -2401,7 +2485,7 @@ pub mod tests { &program_with_deps, ); - assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + assert!(matches!(result, Err(LeeError::CircuitProvingError(_)))); } /// Exploit-scenario pin. A single `(program_id, seed)` pair can derive a family of @@ -2418,8 +2502,8 @@ pub mod tests { let keys_a = test_private_account_keys_1(); let keys_b = test_private_account_keys_2(); let seed = PdaSeed::new([55; 32]); - let shared_a = SharedSecretKey::new([66; 32], &keys_a.vpk()); - let shared_b = SharedSecretKey::new([77; 32], &keys_b.vpk()); + let shared_a = SharedSecretKey::encapsulate_deterministic(&keys_a.vpk(), &[0_u8; 32], 0).0; + let shared_b = SharedSecretKey::encapsulate_deterministic(&keys_b.vpk(), &[0_u8; 32], 0).0; let account_a = AccountId::for_private_pda(&program.id(), &seed, &keys_a.npk(), u128::MAX); let account_b = AccountId::for_private_pda(&program.id(), &seed, &keys_b.npk(), u128::MAX); @@ -2447,7 +2531,7 @@ pub mod tests { &program.into(), ); - assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + assert!(matches!(result, Err(LeeError::CircuitProvingError(_)))); } /// A private PDA that is reused at top level without an external seed in the identity still @@ -2460,7 +2544,8 @@ pub mod tests { let program = Program::noop(); let keys = test_private_account_keys_1(); let npk = keys.npk(); - let shared_secret = SharedSecretKey::new([55; 32], &keys.vpk()); + let shared_secret = + SharedSecretKey::encapsulate_deterministic(&keys.vpk(), &[0_u8; 32], 0).0; let seed = PdaSeed::new([99; 32]); // Simulate a previously-claimed private PDA: program_owner != DEFAULT, is_authorized = @@ -2487,7 +2572,7 @@ pub mod tests { &program.into(), ); - assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + assert!(matches!(result, Err(LeeError::CircuitProvingError(_)))); } #[test] @@ -2538,8 +2623,8 @@ pub mod tests { let result = state.transition_from_privacy_preserving_transaction(&tx, 1, 0); - assert!(matches!(result, Err(NssaError::InvalidInput(_)))); - let NssaError::InvalidInput(error_message) = result.err().unwrap() else { + assert!(matches!(result, Err(LeeError::InvalidInput(_)))); + let LeeError::InvalidInput(error_message) = result.err().unwrap() else { panic!("Incorrect message error"); }; let expected_error_message = "Nullifier already seen".to_owned(); @@ -2560,7 +2645,8 @@ pub mod tests { (&sender_keys.npk(), 0), ); - let shared_secret = SharedSecretKey::new([55; 32], &sender_keys.vpk()); + let shared_secret = + SharedSecretKey::encapsulate_deterministic(&sender_keys.vpk(), &[0_u8; 32], 0).0; let result = execute_and_prove( vec![private_account_1.clone(), private_account_1], Program::serialize_instruction(100_u128).unwrap(), @@ -2581,7 +2667,7 @@ pub mod tests { &program.into(), ); - assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + assert!(matches!(result, Err(LeeError::CircuitProvingError(_)))); } #[test] @@ -2646,7 +2732,7 @@ pub mod tests { let result = state.transition_from_public_transaction(&tx, 2, 0); - assert!(matches!(result, Err(NssaError::InvalidProgramBehavior(_)))); + assert!(matches!(result, Err(LeeError::InvalidProgramBehavior(_)))); assert_eq!(state.get_account_by_id(account_id), Account::default()); } @@ -2760,7 +2846,7 @@ pub mod tests { let result = state.transition_from_public_transaction(&tx, 1, 0); assert!(matches!( result, - Err(NssaError::MaxChainedCallsDepthExceeded) + Err(LeeError::MaxChainedCallsDepthExceeded) )); } @@ -2876,7 +2962,7 @@ pub mod tests { &program.into(), ); - assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + assert!(matches!(result, Err(LeeError::CircuitProvingError(_)))); } #[test] @@ -2904,9 +2990,8 @@ pub mod tests { AccountId::from(&PublicKey::new_from_private_key(&recipient_private_key)); let recipient_pre = AccountWithMetadata::new(Account::default(), true, recipient_account_id); - let esk = [5; 32]; - let shared_secret = SharedSecretKey::new(esk, &sender_keys.vpk()); - let epk = EphemeralPublicKey::from_scalar(esk); + let (shared_secret, epk) = + SharedSecretKey::encapsulate_deterministic(&sender_keys.vpk(), &[0_u8; 32], 0); let balance = 37; @@ -3010,13 +3095,11 @@ pub mod tests { None, ); - let from_esk = [3; 32]; - let from_ss = SharedSecretKey::new(from_esk, &from_keys.vpk()); - let from_epk = EphemeralPublicKey::from_scalar(from_esk); + let (from_ss, from_epk) = + SharedSecretKey::encapsulate_deterministic(&from_keys.vpk(), &[0_u8; 32], 0); - let to_esk = [3; 32]; - let to_ss = SharedSecretKey::new(to_esk, &to_keys.vpk()); - let to_epk = EphemeralPublicKey::from_scalar(to_esk); + let (to_ss, to_epk) = + SharedSecretKey::encapsulate_deterministic(&to_keys.vpk(), &[0_u8; 32], 1); let mut dependencies = HashMap::new(); @@ -3212,7 +3295,7 @@ pub mod tests { assert!(matches!( result, - Err(NssaError::InvalidProgramBehavior( + Err(LeeError::InvalidProgramBehavior( InvalidProgramBehaviorError::ClaimedNonDefaultAccount { account_id: err_account_id } )) if err_account_id == account_id )); @@ -3271,7 +3354,7 @@ pub mod tests { .unwrap(); assert!(matches!( res, - Err(NssaError::InvalidProgramBehavior( + Err(LeeError::InvalidProgramBehavior( InvalidProgramBehaviorError::ExecutionValidationFailed( ExecutionValidationError::MismatchedTotalBalance { total_balance_pre_states, total_balance_post_states } ) @@ -3313,9 +3396,8 @@ pub mod tests { let program = Program::authenticated_transfer_program(); // Set up parameters for the new account - let esk = [3; 32]; - let shared_secret = SharedSecretKey::new(esk, &private_keys.vpk()); - let epk = EphemeralPublicKey::from_scalar(esk); + let (shared_secret, epk) = + SharedSecretKey::encapsulate_deterministic(&private_keys.vpk(), &[0_u8; 32], 0); let instruction = authenticated_transfer_core::Instruction::Initialize; @@ -3365,9 +3447,8 @@ pub mod tests { AccountWithMetadata::new(Account::default(), false, (&private_keys.npk(), 0)); let program = Program::claimer(); - let esk = [5; 32]; - let shared_secret = SharedSecretKey::new(esk, &private_keys.vpk()); - let epk = EphemeralPublicKey::from_scalar(esk); + let (shared_secret, epk) = + SharedSecretKey::encapsulate_deterministic(&private_keys.vpk(), &[0_u8; 32], 0); let (output, proof) = execute_and_prove( vec![unauthorized_account], @@ -3415,9 +3496,8 @@ pub mod tests { let claimer_program = Program::claimer(); // Set up parameters for claiming the new account - let esk = [3; 32]; - let shared_secret = SharedSecretKey::new(esk, &private_keys.vpk()); - let epk = EphemeralPublicKey::from_scalar(esk); + let (shared_secret, epk) = + SharedSecretKey::encapsulate_deterministic(&private_keys.vpk(), &[0_u8; 32], 0); let instruction = authenticated_transfer_core::Instruction::Initialize; @@ -3465,8 +3545,8 @@ pub mod tests { }; let noop_program = Program::noop(); - let esk2 = [4; 32]; - let shared_secret2 = SharedSecretKey::new(esk2, &private_keys.vpk()); + let shared_secret2 = + SharedSecretKey::encapsulate_deterministic(&private_keys.vpk(), &[0_u8; 32], 0).0; // Step 3: Try to execute noop program with authentication but without initialization let res = execute_and_prove( @@ -3480,7 +3560,7 @@ pub mod tests { &noop_program.into(), ); - assert!(matches!(res, Err(NssaError::CircuitProvingError(_)))); + assert!(matches!(res, Err(LeeError::CircuitProvingError(_)))); } #[test] @@ -3529,7 +3609,7 @@ pub mod tests { // Should fail - cannot modify data without claiming the account assert!(matches!( result, - Err(NssaError::InvalidProgramBehavior( + Err(LeeError::InvalidProgramBehavior( InvalidProgramBehaviorError::DefaultAccountModifiedWithoutClaim { account_id: err_account_id } @@ -3550,7 +3630,8 @@ pub mod tests { vec![private_account], Program::serialize_instruction(instruction).unwrap(), vec![InputAccountIdentity::PrivateAuthorizedUpdate { - ssk: SharedSecretKey::new([3; 32], &sender_keys.vpk()), + ssk: SharedSecretKey::encapsulate_deterministic(&sender_keys.vpk(), &[0_u8; 32], 0) + .0, nsk: sender_keys.nsk, membership_proof: (0, vec![]), identifier: 0, @@ -3576,7 +3657,8 @@ pub mod tests { vec![private_account], Program::serialize_instruction(instruction).unwrap(), vec![InputAccountIdentity::PrivateAuthorizedUpdate { - ssk: SharedSecretKey::new([3; 32], &sender_keys.vpk()), + ssk: SharedSecretKey::encapsulate_deterministic(&sender_keys.vpk(), &[0_u8; 32], 0) + .0, nsk: sender_keys.nsk, membership_proof: (0, vec![]), identifier: 0, @@ -3585,7 +3667,7 @@ pub mod tests { ); // Should fail - cannot modify data without claiming the account - assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + assert!(matches!(result, Err(LeeError::CircuitProvingError(_)))); } #[test] @@ -3622,8 +3704,8 @@ pub mod tests { let balance_to_transfer = 10_u128; let instruction = (balance_to_transfer, auth_transfers.id()); - let recipient_esk = [3; 32]; - let recipient = SharedSecretKey::new(recipient_esk, &recipient_keys.vpk()); + let recipient = + SharedSecretKey::encapsulate_deterministic(&recipient_keys.vpk(), &[0_u8; 32], 0).0; let mut dependencies = HashMap::new(); dependencies.insert(auth_transfers.id(), auth_transfers); @@ -3648,7 +3730,7 @@ pub mod tests { ); // Assert - should fail because the malicious program tries to manipulate is_authorized - assert!(matches!(result, Err(NssaError::CircuitProvingError(_)))); + assert!(matches!(result, Err(LeeError::CircuitProvingError(_)))); } #[test_case::test_case((Some(1), Some(3)), 3; "at upper bound")] @@ -3698,7 +3780,7 @@ pub mod tests { if is_inside_validity_window { assert!(result.is_ok()); } else { - assert!(matches!(result, Err(NssaError::OutOfValidityWindow))); + assert!(matches!(result, Err(LeeError::OutOfValidityWindow))); } } @@ -3752,7 +3834,7 @@ pub mod tests { if is_inside_validity_window { assert!(result.is_ok()); } else { - assert!(matches!(result, Err(NssaError::OutOfValidityWindow))); + assert!(matches!(result, Err(LeeError::OutOfValidityWindow))); } } @@ -3779,9 +3861,8 @@ pub mod tests { let pre = AccountWithMetadata::new(Account::default(), false, (&account_keys.npk(), 0)); let mut state = V03State::new_with_genesis_accounts(&[], vec![], 0).with_test_programs(); let tx = { - let esk = [3; 32]; - let shared_secret = SharedSecretKey::new(esk, &account_keys.vpk()); - let epk = EphemeralPublicKey::from_scalar(esk); + let (shared_secret, epk) = + SharedSecretKey::encapsulate_deterministic(&account_keys.vpk(), &[0_u8; 32], 0); let instruction = ( block_validity_window, @@ -3821,7 +3902,7 @@ pub mod tests { if is_inside_validity_window { assert!(result.is_ok()); } else { - assert!(matches!(result, Err(NssaError::OutOfValidityWindow))); + assert!(matches!(result, Err(LeeError::OutOfValidityWindow))); } } @@ -3849,9 +3930,8 @@ pub mod tests { let pre = AccountWithMetadata::new(Account::default(), false, (&account_keys.npk(), 0)); let mut state = V03State::new_with_genesis_accounts(&[], vec![], 0).with_test_programs(); let tx = { - let esk = [3; 32]; - let shared_secret = SharedSecretKey::new(esk, &account_keys.vpk()); - let epk = EphemeralPublicKey::from_scalar(esk); + let (shared_secret, epk) = + SharedSecretKey::encapsulate_deterministic(&account_keys.vpk(), &[0_u8; 32], 0); let instruction = ( BlockValidityWindow::new_unbounded(), @@ -3893,7 +3973,7 @@ pub mod tests { if is_inside_validity_window { assert!(result.is_ok()); } else { - assert!(matches!(result, Err(NssaError::OutOfValidityWindow))); + assert!(matches!(result, Err(LeeError::OutOfValidityWindow))); } } @@ -4405,8 +4485,10 @@ pub mod tests { ..Account::default() }; - let alice_shared_0 = SharedSecretKey::new([10; 32], &alice_keys.vpk()); - let alice_shared_1 = SharedSecretKey::new([11; 32], &alice_keys.vpk()); + let (alice_shared_0, alice_epk_0) = + SharedSecretKey::encapsulate_deterministic(&alice_keys.vpk(), &[0_u8; 32], 0); + let (alice_shared_1, alice_epk_1) = + SharedSecretKey::encapsulate_deterministic(&alice_keys.vpk(), &[0_u8; 32], 1); // Fund alice_pda_0 via authenticated_transfer directly. { @@ -4434,11 +4516,7 @@ pub mod tests { let message = Message::try_from_circuit_output( vec![funder_id], vec![funder_nonce], - vec![( - alice_npk, - alice_keys.vpk(), - EphemeralPublicKey::from_scalar([10; 32]), - )], + vec![(alice_npk, alice_keys.vpk(), alice_epk_0.clone())], output, ) .unwrap(); @@ -4478,11 +4556,7 @@ pub mod tests { let message = Message::try_from_circuit_output( vec![funder_id], vec![funder_nonce], - vec![( - alice_npk, - alice_keys.vpk(), - EphemeralPublicKey::from_scalar([11; 32]), - )], + vec![(alice_npk, alice_keys.vpk(), alice_epk_1.clone())], output, ) .unwrap(); @@ -4529,11 +4603,7 @@ pub mod tests { let message = Message::try_from_circuit_output( vec![recipient_id], vec![Nonce(0)], - vec![( - alice_npk, - alice_keys.vpk(), - EphemeralPublicKey::from_scalar([10; 32]), - )], + vec![(alice_npk, alice_keys.vpk(), alice_epk_0)], output, ) .unwrap(); @@ -4574,11 +4644,7 @@ pub mod tests { let message = Message::try_from_circuit_output( vec![recipient_id], vec![], - vec![( - alice_npk, - alice_keys.vpk(), - EphemeralPublicKey::from_scalar([11; 32]), - )], + vec![(alice_npk, alice_keys.vpk(), alice_epk_1)], output, ) .unwrap(); @@ -4606,7 +4672,7 @@ pub mod tests { }; let commitment_pda_1_after_spend = Commitment::new(&alice_pda_1_id, &alice_pda_1_account_after_spend); - let alice_shared_1_refund = SharedSecretKey::new([12; 32], &alice_keys.vpk()); + let alice_shared_1_refund = SharedSecretKey([12; 32]); { let recipient_account = state.get_account_by_id(recipient_id); let recipient_nonce = recipient_account.nonce; @@ -4642,7 +4708,7 @@ pub mod tests { vec![( alice_npk, alice_keys.vpk(), - EphemeralPublicKey::from_scalar([12; 32]), + EphemeralPublicKey(vec![12_u8; 1088]), )], output, ) diff --git a/nssa/src/validated_state_diff.rs b/lee/state_machine/src/validated_state_diff.rs similarity index 88% rename from nssa/src/validated_state_diff.rs rename to lee/state_machine/src/validated_state_diff.rs index 87bde206..c26ac3e7 100644 --- a/nssa/src/validated_state_diff.rs +++ b/lee/state_machine/src/validated_state_diff.rs @@ -3,8 +3,7 @@ use std::{ hash::Hash, }; -use log::debug; -use nssa_core::{ +use lee_core::{ BlockId, Commitment, Nullifier, PrivacyPreservingCircuitOutput, Timestamp, account::{Account, AccountId, AccountWithMetadata}, program::{ @@ -12,10 +11,11 @@ use nssa_core::{ validate_execution, }, }; +use log::debug; use crate::{ V03State, ensure, - error::{InvalidProgramBehaviorError, NssaError}, + error::{InvalidProgramBehaviorError, LeeError}, privacy_preserving_transaction::{ PrivacyPreservingTransaction, circuit::Proof, message::Message, }, @@ -45,20 +45,20 @@ impl ValidatedStateDiff { state: &V03State, block_id: BlockId, timestamp: Timestamp, - ) -> Result { + ) -> Result { let message = tx.message(); let witness_set = tx.witness_set(); // All account_ids must be different ensure!( message.account_ids.iter().collect::>().len() == message.account_ids.len(), - NssaError::InvalidInput("Duplicate account_ids found in message".into(),) + LeeError::InvalidInput("Duplicate account_ids found in message".into(),) ); // Check exactly one nonce is provided for each signature ensure!( message.nonces.len() == witness_set.signatures_and_public_keys.len(), - NssaError::InvalidInput( + LeeError::InvalidInput( "Mismatch between number of nonces and signatures/public keys".into(), ) ); @@ -66,7 +66,7 @@ impl ValidatedStateDiff { // Check the signatures are valid ensure!( witness_set.is_valid_for(message), - NssaError::InvalidInput("Invalid signature for given message and public key".into()) + LeeError::InvalidInput("Invalid signature for given message and public key".into()) ); let signer_account_ids = tx.signer_account_ids(); @@ -75,7 +75,7 @@ impl ValidatedStateDiff { let current_nonce = state.get_account_by_id(*account_id).nonce; ensure!( current_nonce == *nonce, - NssaError::InvalidInput("Nonce mismatch".into()) + LeeError::InvalidInput("Nonce mismatch".into()) ); } @@ -123,12 +123,12 @@ impl ValidatedStateDiff { while let Some((chained_call, caller_data)) = chained_calls.pop_front() { ensure!( chain_calls_counter <= MAX_NUMBER_CHAINED_CALLS, - NssaError::MaxChainedCallsDepthExceeded + LeeError::MaxChainedCallsDepthExceeded ); // Check that the `program_id` corresponds to a deployed program let Some(program) = state.programs().get(&chained_call.program_id) else { - return Err(NssaError::InvalidInput("Unknown program".into())); + return Err(LeeError::InvalidInput("Unknown program".into())); }; debug!( @@ -173,12 +173,18 @@ impl ValidatedStateDiff { ); // Check that the program output pre_states marked as authorized are indeed - // authorized. + // authorized, and vice-versa. let is_indeed_authorized = is_authorized(&account_id); ensure!( !pre.is_authorized || is_indeed_authorized, InvalidProgramBehaviorError::InvalidAccountAuthorization { account_id } ); + ensure!( + pre.is_authorized || !is_indeed_authorized, + InvalidProgramBehaviorError::AuthorizedAccountMarkedAsNotAuthorized { + account_id + } + ); } // Verify that the program output's self_program_id matches the expected program ID. @@ -214,7 +220,7 @@ impl ValidatedStateDiff { && program_output .timestamp_validity_window .is_valid_for(timestamp), - NssaError::OutOfValidityWindow + LeeError::OutOfValidityWindow ); for (i, post) in program_output.post_states.iter_mut().enumerate() { @@ -269,11 +275,20 @@ impl ValidatedStateDiff { // the loop above already gates program_output's `is_authorized` via the // `!pre.is_authorized || is_indeed_authorized` check, while `chained_call. // pre_states` is caller-controlled and can be forged (audit-issue 91). - let authorized_accounts: HashSet<_> = program_output - .pre_states - .iter() - .filter(|pre| pre.is_authorized) - .map(|pre| pre.account_id) + // + // Union with the caller's authorized set so that authorization is monotonically + // growing: once an account is authorized at any point in the chain it remains + // authorized for all subsequent calls. + let authorized_accounts: HashSet<_> = caller_data + .authorized_accounts + .into_iter() + .chain( + program_output + .pre_states + .iter() + .filter(|pre| pre.is_authorized) + .map(|pre| pre.account_id), + ) .collect(); for new_call in program_output.chained_calls.into_iter().rev() { chained_calls.push_front(( @@ -321,14 +336,14 @@ impl ValidatedStateDiff { state: &V03State, block_id: BlockId, timestamp: Timestamp, - ) -> Result { + ) -> Result { let message = &tx.message; let witness_set = &tx.witness_set; // 1. Commitments or nullifiers are non empty ensure!( !message.new_commitments.is_empty() || !message.new_nullifiers.is_empty(), - NssaError::InvalidInput( + LeeError::InvalidInput( "Empty commitments and empty nullifiers found in message".into(), ) ); @@ -336,26 +351,32 @@ impl ValidatedStateDiff { // 2. Check there are no duplicate account_ids in the public_account_ids list. ensure!( n_unique(&message.public_account_ids) == message.public_account_ids.len(), - NssaError::InvalidInput("Duplicate account_ids found in message".into()) + LeeError::InvalidInput("Duplicate account_ids found in message".into()) ); // Check there are no duplicate nullifiers in the new_nullifiers list ensure!( - n_unique(&message.new_nullifiers) == message.new_nullifiers.len(), - NssaError::InvalidInput("Duplicate nullifiers found in message".into()) + n_unique( + &message + .new_nullifiers + .iter() + .map(|(n, _)| n) + .collect::>() + ) == message.new_nullifiers.len(), + LeeError::InvalidInput("Duplicate nullifiers found in message".into()) ); // Check there are no duplicate commitments in the new_commitments list ensure!( n_unique(&message.new_commitments) == message.new_commitments.len(), - NssaError::InvalidInput("Duplicate commitments found in message".into()) + LeeError::InvalidInput("Duplicate commitments found in message".into()) ); // 3. Nonce checks and Valid signatures // Check exactly one nonce is provided for each signature ensure!( message.nonces.len() == witness_set.signatures_and_public_keys.len(), - NssaError::InvalidInput( + LeeError::InvalidInput( "Mismatch between number of nonces and signatures/public keys".into(), ) ); @@ -363,7 +384,7 @@ impl ValidatedStateDiff { // Check the signatures are valid ensure!( witness_set.signatures_are_valid_for(message), - NssaError::InvalidInput("Invalid signature for given message and public key".into()) + LeeError::InvalidInput("Invalid signature for given message and public key".into()) ); let signer_account_ids = tx.signer_account_ids(); @@ -372,7 +393,7 @@ impl ValidatedStateDiff { let current_nonce = state.get_account_by_id(*account_id).nonce; ensure!( current_nonce == *nonce, - NssaError::InvalidInput("Nonce mismatch".into()) + LeeError::InvalidInput("Nonce mismatch".into()) ); } @@ -380,7 +401,7 @@ impl ValidatedStateDiff { ensure!( message.block_validity_window.is_valid_for(block_id) && message.timestamp_validity_window.is_valid_for(timestamp), - NssaError::OutOfValidityWindow + LeeError::OutOfValidityWindow ); // Build pre_states for proof verification @@ -434,11 +455,11 @@ impl ValidatedStateDiff { pub fn from_program_deployment_transaction( tx: &ProgramDeploymentTransaction, state: &V03State, - ) -> Result { + ) -> Result { // TODO: remove clone let program = Program::new(tx.message.bytecode.clone())?; if state.programs().contains_key(&program.id()) { - return Err(NssaError::ProgramAlreadyExists); + return Err(LeeError::ProgramAlreadyExists); } Ok(Self(StateDiff { signer_account_ids: vec![], @@ -467,7 +488,7 @@ fn check_privacy_preserving_circuit_proof_is_valid( proof: &Proof, public_pre_states: &[AccountWithMetadata], message: &Message, -) -> Result<(), NssaError> { +) -> Result<(), LeeError> { let output = PrivacyPreservingCircuitOutput { public_pre_states: public_pre_states.to_vec(), public_post_states: message.public_post_states.clone(), @@ -485,7 +506,7 @@ fn check_privacy_preserving_circuit_proof_is_valid( proof .is_valid_for(&output) .then_some(()) - .ok_or(NssaError::InvalidPrivacyPreservingProof) + .ok_or(LeeError::InvalidPrivacyPreservingProof) } fn n_unique(data: &[T]) -> usize { @@ -495,11 +516,11 @@ fn n_unique(data: &[T]) -> usize { #[cfg(test)] mod tests { - use nssa_core::account::{AccountId, Nonce}; + use lee_core::account::{AccountId, Nonce}; use crate::{ PrivateKey, PublicKey, V03State, - error::{InvalidProgramBehaviorError, NssaError}, + error::{InvalidProgramBehaviorError, LeeError}, program::Program, public_transaction::{Message, WitnessSet}, validated_state_diff::ValidatedStateDiff, @@ -520,10 +541,9 @@ mod tests { /// returns an error before any state is applied. #[test] fn privacy_malicious_programs_cannot_drain_public_victim() { - use nssa_core::{ + use lee_core::{ Commitment, InputAccountIdentity, SharedSecretKey, account::{Account, AccountWithMetadata}, - encryption::EphemeralPublicKey, }; use crate::{ @@ -537,22 +557,20 @@ mod tests { }; type InjectorInstruction = ( - nssa_core::program::ProgramId, // p2_id - nssa_core::program::ProgramId, // auth_transfer_id - [u8; 32], // victim_id_raw - u128, // victim_balance - u128, // victim_nonce - nssa_core::program::ProgramId, // victim_program_owner - [u8; 32], // recipient_id_raw - u128, // amount + lee_core::program::ProgramId, // p2_id + lee_core::program::ProgramId, // auth_transfer_id + [u8; 32], // victim_id_raw + u128, // victim_balance + u128, // victim_nonce + lee_core::program::ProgramId, // victim_program_owner + [u8; 32], // recipient_id_raw + u128, // amount ); // Attacker controls a private account. let attacker_keys = test_private_account_keys_1(); let attacker_id = AccountId::for_regular_private_account(&attacker_keys.npk(), 0); - let attacker_esk = [12_u8; 32]; - let attacker_ssk = SharedSecretKey::new(attacker_esk, &attacker_keys.vpk()); - let attacker_epk = EphemeralPublicKey::from_scalar(attacker_esk); + let (attacker_ssk, attacker_epk) = SharedSecretKey::encapsulate(&attacker_keys.vpk()); let victim_id = AccountId::new([20_u8; 32]); let recipient_id = AccountId::new([42_u8; 32]); @@ -643,7 +661,7 @@ mod tests { let result = ValidatedStateDiff::from_privacy_preserving_transaction(&tx, &state, 1, 0); assert!( - matches!(result, Err(NssaError::InvalidPrivacyPreservingProof)), + matches!(result, Err(LeeError::InvalidPrivacyPreservingProof)), "attack privacy transaction should be rejected with InvalidPrivacyPreservingProof" ); assert_eq!(state.get_account_by_id(victim_id).balance, victim_balance); @@ -671,10 +689,9 @@ mod tests { /// test exercises this route. #[test] fn privacy_malicious_programs_cannot_drain_private_victim() { - use nssa_core::{ + use lee_core::{ Commitment, InputAccountIdentity, SharedSecretKey, account::{Account, AccountWithMetadata}, - encryption::EphemeralPublicKey, }; use crate::{ @@ -691,22 +708,20 @@ mod tests { }; type InjectorInstruction = ( - nssa_core::program::ProgramId, // p2_id - nssa_core::program::ProgramId, // auth_transfer_id - [u8; 32], // victim_id_raw - u128, // victim_balance - u128, // victim_nonce - nssa_core::program::ProgramId, // victim_program_owner - [u8; 32], // recipient_id_raw - u128, // amount + lee_core::program::ProgramId, // p2_id + lee_core::program::ProgramId, // auth_transfer_id + [u8; 32], // victim_id_raw + u128, // victim_balance + u128, // victim_nonce + lee_core::program::ProgramId, // victim_program_owner + [u8; 32], // recipient_id_raw + u128, // amount ); // Attacker controls a private account. let attacker_keys = test_private_account_keys_1(); let attacker_id = AccountId::for_regular_private_account(&attacker_keys.npk(), 0); - let attacker_esk = [12_u8; 32]; - let attacker_ssk = SharedSecretKey::new(attacker_esk, &attacker_keys.vpk()); - let attacker_epk = EphemeralPublicKey::from_scalar(attacker_esk); + let (attacker_ssk, attacker_epk) = SharedSecretKey::encapsulate(&attacker_keys.vpk()); // Victim is a private account — not registered in public chain state. let victim_keys = test_private_account_keys_2(); @@ -803,7 +818,7 @@ mod tests { let result = ValidatedStateDiff::from_privacy_preserving_transaction(&tx, &state, 1, 0); assert!( - matches!(result, Err(NssaError::InvalidPrivacyPreservingProof)), + matches!(result, Err(LeeError::InvalidPrivacyPreservingProof)), "attack on private victim should be rejected with InvalidPrivacyPreservingProof" ); // Victim has no public balance to check; confirming the recipient received nothing @@ -833,14 +848,14 @@ mod tests { // Primitives only — AccountId/Account cannot round-trip through instruction_data // via risc0_zkvm::serde (SerializeDisplay issue). type InjectorInstruction = ( - nssa_core::program::ProgramId, // p2_id - nssa_core::program::ProgramId, // auth_transfer_id - [u8; 32], // victim_id_raw - u128, // victim_balance - u128, // victim_nonce - nssa_core::program::ProgramId, // victim_program_owner - [u8; 32], // recipient_id_raw - u128, // amount + lee_core::program::ProgramId, // p2_id + lee_core::program::ProgramId, // auth_transfer_id + [u8; 32], // victim_id_raw + u128, // victim_balance + u128, // victim_nonce + lee_core::program::ProgramId, // victim_program_owner + [u8; 32], // recipient_id_raw + u128, // amount ); let attacker_key = PrivateKey::try_new([10; 32]).unwrap(); @@ -895,7 +910,7 @@ mod tests { assert!( matches!( result, - Err(NssaError::InvalidProgramBehavior( + Err(LeeError::InvalidProgramBehavior( InvalidProgramBehaviorError::InvalidAccountAuthorization { account_id } )) if account_id == victim_id ), diff --git a/lez/Cargo.toml b/lez/Cargo.toml new file mode 100644 index 00000000..40aa19df --- /dev/null +++ b/lez/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "lez" +version = "0.1.0" +edition = "2024" +license = { workspace = true } + +[lints] +workspace = true + +[dependencies] +sequencer_core.workspace = true +indexer_core.workspace = true diff --git a/common/Cargo.toml b/lez/common/Cargo.toml similarity index 90% rename from common/Cargo.toml rename to lez/common/Cargo.toml index 5d8e278c..a559960d 100644 --- a/common/Cargo.toml +++ b/lez/common/Cargo.toml @@ -8,8 +8,8 @@ license = { workspace = true } workspace = true [dependencies] -nssa.workspace = true -nssa_core.workspace = true +lee.workspace = true +lee_core.workspace = true authenticated_transfer_core.workspace = true clock_core.workspace = true diff --git a/common/src/block.rs b/lez/common/src/block.rs similarity index 91% rename from common/src/block.rs rename to lez/common/src/block.rs index fbc4c9a6..8f82c56a 100644 --- a/common/src/block.rs +++ b/lez/common/src/block.rs @@ -1,10 +1,10 @@ use borsh::{BorshDeserialize, BorshSerialize}; -use nssa_core::BlockId; -pub use nssa_core::Timestamp; +use lee_core::BlockId; +pub use lee_core::Timestamp; use serde::{Deserialize, Serialize}; use sha2::{Digest as _, Sha256, digest::FixedOutput as _}; -use crate::{HashType, transaction::NSSATransaction}; +use crate::{HashType, transaction::LeeTransaction}; pub type MantleMsgId = [u8; 32]; pub type BlockHash = HashType; @@ -35,12 +35,12 @@ pub struct BlockHeader { pub prev_block_hash: BlockHash, pub hash: BlockHash, pub timestamp: Timestamp, - pub signature: nssa::Signature, + pub signature: lee::Signature, } #[derive(Debug, Clone, BorshSerialize, BorshDeserialize)] pub struct BlockBody { - pub transactions: Vec, + pub transactions: Vec, } #[derive(Debug, Clone, BorshSerialize, BorshDeserialize)] @@ -75,14 +75,14 @@ pub struct HashableBlockData { pub block_id: BlockId, pub prev_block_hash: BlockHash, pub timestamp: Timestamp, - pub transactions: Vec, + pub transactions: Vec, } impl HashableBlockData { #[must_use] pub fn into_pending_block( self, - signing_key: &nssa::PrivateKey, + signing_key: &lee::PrivateKey, bedrock_parent_id: MantleMsgId, ) -> Block { const PREFIX: &[u8; 32] = b"/LEE/v0.3/Message/Block/\x00\x00\x00\x00\x00\x00\x00\x00"; @@ -98,7 +98,7 @@ impl HashableBlockData { bytes.extend_from_slice(&data_bytes); let hash = OwnHasher::hash(&bytes); - let signature = nssa::Signature::new(signing_key, &hash.0); + let signature = lee::Signature::new(signing_key, &hash.0); Block { header: BlockHeader { block_id: self.block_id, diff --git a/common/src/borsh_base64.rs b/lez/common/src/borsh_base64.rs similarity index 100% rename from common/src/borsh_base64.rs rename to lez/common/src/borsh_base64.rs diff --git a/common/src/config.rs b/lez/common/src/config.rs similarity index 100% rename from common/src/config.rs rename to lez/common/src/config.rs diff --git a/common/src/lib.rs b/lez/common/src/lib.rs similarity index 100% rename from common/src/lib.rs rename to lez/common/src/lib.rs diff --git a/common/src/test_utils.rs b/lez/common/src/test_utils.rs similarity index 54% rename from common/src/test_utils.rs rename to lez/common/src/test_utils.rs index 806048e1..f4e185ea 100644 --- a/common/src/test_utils.rs +++ b/lez/common/src/test_utils.rs @@ -1,16 +1,16 @@ -use nssa::AccountId; +use lee::AccountId; use crate::{ HashType, block::{Block, HashableBlockData}, - transaction::{NSSATransaction, clock_invocation}, + transaction::{LeeTransaction, clock_invocation}, }; // Helpers #[must_use] -pub fn sequencer_sign_key_for_testing() -> nssa::PrivateKey { - nssa::PrivateKey::try_new([37; 32]).unwrap() +pub fn sequencer_sign_key_for_testing() -> lee::PrivateKey { + lee::PrivateKey::try_new([37; 32]).unwrap() } // Dummy producers @@ -26,9 +26,9 @@ pub fn sequencer_sign_key_for_testing() -> nssa::PrivateKey { pub fn produce_dummy_block( id: u64, prev_hash: Option, - mut transactions: Vec, + mut transactions: Vec, ) -> Block { - transactions.push(NSSATransaction::Public(clock_invocation( + transactions.push(LeeTransaction::Public(clock_invocation( id.saturating_mul(100), ))); @@ -43,23 +43,23 @@ pub fn produce_dummy_block( } #[must_use] -pub fn produce_dummy_empty_transaction() -> NSSATransaction { - let program_id = nssa::program::Program::authenticated_transfer_program().id(); +pub fn produce_dummy_empty_transaction() -> LeeTransaction { + let program_id = lee::program::Program::authenticated_transfer_program().id(); let account_ids = vec![]; let nonces = vec![]; - let message = nssa::public_transaction::Message::try_new( + let message = lee::public_transaction::Message::try_new( program_id, account_ids, nonces, authenticated_transfer_core::Instruction::Initialize, ) .unwrap(); - let private_key = nssa::PrivateKey::try_new([1; 32]).unwrap(); - let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[&private_key]); + let private_key = lee::PrivateKey::try_new([1; 32]).unwrap(); + let witness_set = lee::public_transaction::WitnessSet::for_message(&message, &[&private_key]); - let nssa_tx = nssa::PublicTransaction::new(message, witness_set); + let lee_tx = lee::PublicTransaction::new(message, witness_set); - NSSATransaction::Public(nssa_tx) + LeeTransaction::Public(lee_tx) } #[must_use] @@ -68,12 +68,12 @@ pub fn create_transaction_native_token_transfer( nonce: u128, to: AccountId, balance_to_move: u128, - signing_key: &nssa::PrivateKey, -) -> NSSATransaction { + signing_key: &lee::PrivateKey, +) -> LeeTransaction { let account_ids = vec![from, to]; let nonces = vec![nonce.into()]; - let program_id = nssa::program::Program::authenticated_transfer_program().id(); - let message = nssa::public_transaction::Message::try_new( + let program_id = lee::program::Program::authenticated_transfer_program().id(); + let message = lee::public_transaction::Message::try_new( program_id, account_ids, nonces, @@ -82,9 +82,9 @@ pub fn create_transaction_native_token_transfer( }, ) .unwrap(); - let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[signing_key]); + let witness_set = lee::public_transaction::WitnessSet::for_message(&message, &[signing_key]); - let nssa_tx = nssa::PublicTransaction::new(message, witness_set); + let lee_tx = lee::PublicTransaction::new(message, witness_set); - NSSATransaction::Public(nssa_tx) + LeeTransaction::Public(lee_tx) } diff --git a/common/src/transaction.rs b/lez/common/src/transaction.rs similarity index 70% rename from common/src/transaction.rs rename to lez/common/src/transaction.rs index 21cbfd75..42a7b761 100644 --- a/common/src/transaction.rs +++ b/lez/common/src/transaction.rs @@ -1,31 +1,31 @@ use borsh::{BorshDeserialize, BorshSerialize}; +use lee::{AccountId, V03State, ValidatedStateDiff}; +use lee_core::{BlockId, Timestamp}; use log::warn; -use nssa::{AccountId, V03State, ValidatedStateDiff}; -use nssa_core::{BlockId, Timestamp}; use serde::{Deserialize, Serialize}; use crate::HashType; #[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] -pub enum NSSATransaction { - Public(nssa::PublicTransaction), - PrivacyPreserving(nssa::PrivacyPreservingTransaction), - ProgramDeployment(nssa::ProgramDeploymentTransaction), +pub enum LeeTransaction { + Public(lee::PublicTransaction), + PrivacyPreserving(lee::PrivacyPreservingTransaction), + ProgramDeployment(lee::ProgramDeploymentTransaction), } -impl Serialize for NSSATransaction { +impl Serialize for LeeTransaction { fn serialize(&self, serializer: S) -> Result { crate::borsh_base64::serialize(self, serializer) } } -impl<'de> Deserialize<'de> for NSSATransaction { +impl<'de> Deserialize<'de> for LeeTransaction { fn deserialize>(deserializer: D) -> Result { crate::borsh_base64::deserialize(deserializer) } } -impl NSSATransaction { +impl LeeTransaction { #[must_use] pub fn hash(&self) -> HashType { HashType(match self { @@ -67,7 +67,7 @@ impl NSSATransaction { } /// Validates the transaction against the current state and returns the resulting diff - /// without applying it. Rejects transactions that modify clock or faucet system accounts, + /// without applying it. Rejects transactions that modify clock, faucet or bridge accounts, /// whether directly or indirectly via chain calls. /// /// This check is required for all user transactions. Only sequencer transactions may bypass @@ -77,7 +77,7 @@ impl NSSATransaction { state: &V03State, block_id: BlockId, timestamp: Timestamp, - ) -> Result { + ) -> Result { let diff = match self { Self::Public(tx) => { ValidatedStateDiff::from_public_transaction(tx, state, block_id, timestamp) @@ -90,26 +90,12 @@ impl NSSATransaction { } }?; - let public_diff = diff.public_diff(); - let touches_clock = nssa::CLOCK_PROGRAM_ACCOUNT_IDS.iter().any(|id| { - public_diff - .get(id) - .is_some_and(|post| *post != state.get_account_by_id(*id)) - }); - if touches_clock { - return Err(nssa::error::NssaError::InvalidInput( - "Transaction modifies system clock accounts".into(), - )); - } - - let faucet_id = nssa::system_faucet_account_id(); - if public_diff - .get(&faucet_id) - .is_some_and(|post| *post != state.get_account_by_id(faucet_id)) - { - return Err(nssa::error::NssaError::InvalidInput( - "Transaction modifies system faucet account".into(), - )); + let system_accounts = lee::CLOCK_PROGRAM_ACCOUNT_IDS.iter().copied().chain([ + lee::system_faucet_account_id(), + lee::system_bridge_account_id(), + ]); + for account_id in system_accounts { + validate_doesnt_modify_account(state, &diff, account_id)?; } Ok(diff) @@ -122,7 +108,7 @@ impl NSSATransaction { state: &mut V03State, block_id: BlockId, timestamp: Timestamp, - ) -> Result { + ) -> Result { let diff = self .validate_on_state(state, block_id, timestamp) .inspect_err(|err| warn!("Error at transition {err:#?}"))?; @@ -131,20 +117,20 @@ impl NSSATransaction { } } -impl From for NSSATransaction { - fn from(value: nssa::PublicTransaction) -> Self { +impl From for LeeTransaction { + fn from(value: lee::PublicTransaction) -> Self { Self::Public(value) } } -impl From for NSSATransaction { - fn from(value: nssa::PrivacyPreservingTransaction) -> Self { +impl From for LeeTransaction { + fn from(value: lee::PrivacyPreservingTransaction) -> Self { Self::PrivacyPreserving(value) } } -impl From for NSSATransaction { - fn from(value: nssa::ProgramDeploymentTransaction) -> Self { +impl From for LeeTransaction { + fn from(value: lee::ProgramDeploymentTransaction) -> Self { Self::ProgramDeployment(value) } } @@ -171,16 +157,34 @@ pub enum TransactionMalformationError { /// Returns the canonical Clock Program invocation transaction for the given block timestamp. /// Every valid block must end with exactly one occurrence of this transaction. #[must_use] -pub fn clock_invocation(timestamp: clock_core::Instruction) -> nssa::PublicTransaction { - let message = nssa::public_transaction::Message::try_new( - nssa::program::Program::clock().id(), +pub fn clock_invocation(timestamp: clock_core::Instruction) -> lee::PublicTransaction { + let message = lee::public_transaction::Message::try_new( + lee::program::Program::clock().id(), clock_core::CLOCK_PROGRAM_ACCOUNT_IDS.to_vec(), vec![], timestamp, ) .expect("Clock invocation message should always be constructable"); - nssa::PublicTransaction::new( + lee::PublicTransaction::new( message, - nssa::public_transaction::WitnessSet::from_raw_parts(vec![]), + lee::public_transaction::WitnessSet::from_raw_parts(vec![]), ) } + +fn validate_doesnt_modify_account( + state: &V03State, + diff: &ValidatedStateDiff, + account_id: AccountId, +) -> Result<(), lee::error::LeeError> { + if diff + .public_diff() + .get(&account_id) + .is_some_and(|post| *post != state.get_account_by_id(account_id)) + { + Err(lee::error::LeeError::InvalidInput(format!( + "Transaction modifies restricted system account {account_id}" + ))) + } else { + Ok(()) + } +} diff --git a/configs/docker-all-in-one/indexer_config.json b/lez/configs/docker-all-in-one/indexer_config.json similarity index 100% rename from configs/docker-all-in-one/indexer_config.json rename to lez/configs/docker-all-in-one/indexer_config.json diff --git a/configs/docker-all-in-one/sequencer_config.json b/lez/configs/docker-all-in-one/sequencer_config.json similarity index 93% rename from configs/docker-all-in-one/sequencer_config.json rename to lez/configs/docker-all-in-one/sequencer_config.json index 207f2e79..edb0132a 100644 --- a/configs/docker-all-in-one/sequencer_config.json +++ b/lez/configs/docker-all-in-one/sequencer_config.json @@ -15,6 +15,11 @@ }, "indexer_rpc_url": "ws://indexer_service:8779", "genesis": [ + { + "supply_bridge_account": { + "balance": 1000000 + } + }, { "supply_account": { "account_id": "6iArKUXxhUJqS7kCaPNhwMWt3ro71PDyBj7jwAyE2VQV", diff --git a/explorer_service/.gitignore b/lez/explorer_service/.gitignore similarity index 100% rename from explorer_service/.gitignore rename to lez/explorer_service/.gitignore diff --git a/explorer_service/Cargo.toml b/lez/explorer_service/Cargo.toml similarity index 100% rename from explorer_service/Cargo.toml rename to lez/explorer_service/Cargo.toml diff --git a/explorer_service/Dockerfile b/lez/explorer_service/Dockerfile similarity index 100% rename from explorer_service/Dockerfile rename to lez/explorer_service/Dockerfile diff --git a/explorer_service/README.md b/lez/explorer_service/README.md similarity index 100% rename from explorer_service/README.md rename to lez/explorer_service/README.md diff --git a/explorer_service/docker-compose.yml b/lez/explorer_service/docker-compose.yml similarity index 88% rename from explorer_service/docker-compose.yml rename to lez/explorer_service/docker-compose.yml index 28c4c9c7..7b699a39 100644 --- a/explorer_service/docker-compose.yml +++ b/lez/explorer_service/docker-compose.yml @@ -1,6 +1,6 @@ services: explorer_service: - image: lssa/explorer_service + image: lez/explorer_service build: context: .. dockerfile: explorer_service/Dockerfile diff --git a/explorer_service/public/explorer.css b/lez/explorer_service/public/explorer.css similarity index 100% rename from explorer_service/public/explorer.css rename to lez/explorer_service/public/explorer.css diff --git a/explorer_service/src/api.rs b/lez/explorer_service/src/api.rs similarity index 100% rename from explorer_service/src/api.rs rename to lez/explorer_service/src/api.rs diff --git a/explorer_service/src/components/account_preview.rs b/lez/explorer_service/src/components/account_preview.rs similarity index 100% rename from explorer_service/src/components/account_preview.rs rename to lez/explorer_service/src/components/account_preview.rs diff --git a/explorer_service/src/components/block_preview.rs b/lez/explorer_service/src/components/block_preview.rs similarity index 100% rename from explorer_service/src/components/block_preview.rs rename to lez/explorer_service/src/components/block_preview.rs diff --git a/explorer_service/src/components/mod.rs b/lez/explorer_service/src/components/mod.rs similarity index 100% rename from explorer_service/src/components/mod.rs rename to lez/explorer_service/src/components/mod.rs diff --git a/explorer_service/src/components/transaction_preview.rs b/lez/explorer_service/src/components/transaction_preview.rs similarity index 100% rename from explorer_service/src/components/transaction_preview.rs rename to lez/explorer_service/src/components/transaction_preview.rs diff --git a/explorer_service/src/format_utils.rs b/lez/explorer_service/src/format_utils.rs similarity index 100% rename from explorer_service/src/format_utils.rs rename to lez/explorer_service/src/format_utils.rs diff --git a/explorer_service/src/lib.rs b/lez/explorer_service/src/lib.rs similarity index 100% rename from explorer_service/src/lib.rs rename to lez/explorer_service/src/lib.rs diff --git a/explorer_service/src/main.rs b/lez/explorer_service/src/main.rs similarity index 100% rename from explorer_service/src/main.rs rename to lez/explorer_service/src/main.rs diff --git a/explorer_service/src/pages/account_page.rs b/lez/explorer_service/src/pages/account_page.rs similarity index 100% rename from explorer_service/src/pages/account_page.rs rename to lez/explorer_service/src/pages/account_page.rs diff --git a/explorer_service/src/pages/block_page.rs b/lez/explorer_service/src/pages/block_page.rs similarity index 100% rename from explorer_service/src/pages/block_page.rs rename to lez/explorer_service/src/pages/block_page.rs diff --git a/explorer_service/src/pages/main_page.rs b/lez/explorer_service/src/pages/main_page.rs similarity index 100% rename from explorer_service/src/pages/main_page.rs rename to lez/explorer_service/src/pages/main_page.rs diff --git a/explorer_service/src/pages/mod.rs b/lez/explorer_service/src/pages/mod.rs similarity index 100% rename from explorer_service/src/pages/mod.rs rename to lez/explorer_service/src/pages/mod.rs diff --git a/explorer_service/src/pages/transaction_page.rs b/lez/explorer_service/src/pages/transaction_page.rs similarity index 100% rename from explorer_service/src/pages/transaction_page.rs rename to lez/explorer_service/src/pages/transaction_page.rs diff --git a/indexer/core/Cargo.toml b/lez/indexer/core/Cargo.toml similarity index 93% rename from indexer/core/Cargo.toml rename to lez/indexer/core/Cargo.toml index 6c7ad01f..c6cc5fc6 100644 --- a/indexer/core/Cargo.toml +++ b/lez/indexer/core/Cargo.toml @@ -10,8 +10,8 @@ workspace = true [dependencies] common.workspace = true logos-blockchain-zone-sdk.workspace = true -nssa.workspace = true -nssa_core.workspace = true +lee.workspace = true +lee_core.workspace = true storage.workspace = true testnet_initial_state.workspace = true diff --git a/indexer/core/src/block_store.rs b/lez/indexer/core/src/block_store.rs similarity index 91% rename from indexer/core/src/block_store.rs rename to lez/indexer/core/src/block_store.rs index b66b778f..d293637c 100644 --- a/indexer/core/src/block_store.rs +++ b/lez/indexer/core/src/block_store.rs @@ -3,13 +3,13 @@ use std::{path::Path, sync::Arc}; use anyhow::{Context as _, Result}; use common::{ block::{BedrockStatus, Block}, - transaction::{NSSATransaction, clock_invocation}, + transaction::{LeeTransaction, clock_invocation}, }; +use lee::{Account, AccountId, V03State}; +use lee_core::BlockId; use log::info; -use logos_blockchain_core::{header::HeaderId, mantle::ops::channel::MsgId}; +use logos_blockchain_core::header::HeaderId; use logos_blockchain_zone_sdk::Slot; -use nssa::{Account, AccountId, V03State}; -use nssa_core::BlockId; use storage::indexer::RocksDBIO; use tokio::sync::RwLock; @@ -53,7 +53,7 @@ impl IndexerStore { Ok(self.dbio.get_block_batch(before, limit)?) } - pub fn get_transaction_by_hash(&self, tx_hash: [u8; 32]) -> Result> { + pub fn get_transaction_by_hash(&self, tx_hash: [u8; 32]) -> Result> { let Some(block_id) = self.dbio.get_block_id_by_tx_hash(tx_hash)? else { return Ok(None); }; @@ -79,7 +79,7 @@ impl IndexerStore { acc_id: [u8; 32], offset: u64, limit: u64, - ) -> Result> { + ) -> Result> { Ok(self.dbio.get_acc_transactions(acc_id, offset, limit)?) } @@ -97,16 +97,16 @@ impl IndexerStore { Ok(self.dbio.calculate_state_for_id(block_id)?) } - pub fn get_zone_cursor(&self) -> Result> { + pub fn get_zone_cursor(&self) -> Result> { let Some(bytes) = self.dbio.get_zone_sdk_indexer_cursor_bytes()? else { return Ok(None); }; - let cursor: (MsgId, Slot) = serde_json::from_slice(&bytes) + let cursor: Slot = serde_json::from_slice(&bytes) .context("Failed to deserialize stored zone-sdk indexer cursor")?; Ok(Some(cursor)) } - pub fn set_zone_cursor(&self, cursor: &(MsgId, Slot)) -> Result<()> { + pub fn set_zone_cursor(&self, cursor: &Slot) -> Result<()> { let bytes = serde_json::to_vec(cursor).context("Failed to serialize zone-sdk indexer cursor")?; self.dbio.put_zone_sdk_indexer_cursor_bytes(&bytes)?; @@ -146,7 +146,7 @@ impl IndexerStore { .ok_or_else(|| anyhow::anyhow!("Block has no transactions"))?; anyhow::ensure!( - *clock_tx == NSSATransaction::Public(clock_invocation(block.header.timestamp)), + *clock_tx == LeeTransaction::Public(clock_invocation(block.header.timestamp)), "Last transaction in block must be the clock invocation for the block timestamp" ); @@ -154,9 +154,9 @@ impl IndexerStore { for transaction in user_txs { if is_genesis { let genesis_tx = match transaction { - NSSATransaction::Public(public_tx) => public_tx, - NSSATransaction::PrivacyPreserving(_) - | NSSATransaction::ProgramDeployment(_) => { + LeeTransaction::Public(public_tx) => public_tx, + LeeTransaction::PrivacyPreserving(_) + | LeeTransaction::ProgramDeployment(_) => { anyhow::bail!("Genesis block should contain only public transactions") } }; @@ -180,7 +180,7 @@ impl IndexerStore { } // Apply the clock invocation directly (it is expected to modify clock accounts). - let NSSATransaction::Public(clock_public_tx) = clock_tx else { + let LeeTransaction::Public(clock_public_tx) = clock_tx else { anyhow::bail!("Clock invocation must be a public transaction"); }; state_guard.transition_from_public_transaction( @@ -231,7 +231,7 @@ mod tests { let sign_key = initial_accounts[0].pub_sign_key.clone(); // Submit genesis block - let clock_tx = NSSATransaction::Public(clock_invocation(0)); + let clock_tx = LeeTransaction::Public(clock_invocation(0)); let genesis_block_data = HashableBlockData { block_id: 1, prev_block_hash: HashType::default(), diff --git a/indexer/core/src/config.rs b/lez/indexer/core/src/config.rs similarity index 100% rename from indexer/core/src/config.rs rename to lez/indexer/core/src/config.rs diff --git a/indexer/core/src/lib.rs b/lez/indexer/core/src/lib.rs similarity index 95% rename from indexer/core/src/lib.rs rename to lez/indexer/core/src/lib.rs index 400d0a9d..b0416905 100644 --- a/indexer/core/src/lib.rs +++ b/lez/indexer/core/src/lib.rs @@ -81,8 +81,8 @@ impl IndexerCore { error!("Failed to deserialize L2 block from zone-sdk: {e}"); // Advance past the broken inscription so we don't // re-process it on restart. - cursor = Some((zone_block.id, slot)); - if let Err(err) = self.store.set_zone_cursor(&(zone_block.id, slot)) { + cursor = Some(slot); + if let Err(err) = self.store.set_zone_cursor(&slot) { warn!("Failed to persist indexer cursor: {err:#}"); } continue; @@ -98,8 +98,8 @@ impl IndexerCore { error!("Failed to store block {}: {err:#}", block.header.block_id); } - cursor = Some((zone_block.id, slot)); - if let Err(err) = self.store.set_zone_cursor(&(zone_block.id, slot)) { + cursor = Some(slot); + if let Err(err) = self.store.set_zone_cursor(&slot) { warn!("Failed to persist indexer cursor: {err:#}"); } yield Ok(block); diff --git a/indexer/ffi/Cargo.toml b/lez/indexer/ffi/Cargo.toml similarity index 96% rename from indexer/ffi/Cargo.toml rename to lez/indexer/ffi/Cargo.toml index 1e6b1468..66f6a518 100644 --- a/indexer/ffi/Cargo.toml +++ b/lez/indexer/ffi/Cargo.toml @@ -5,7 +5,7 @@ name = "indexer_ffi" version = "0.1.0" [dependencies] -nssa.workspace = true +lee.workspace = true indexer_service.workspace = true indexer_service_rpc = { workspace = true, features = ["client"] } indexer_service_protocol.workspace = true diff --git a/indexer/ffi/build.rs b/lez/indexer/ffi/build.rs similarity index 100% rename from indexer/ffi/build.rs rename to lez/indexer/ffi/build.rs diff --git a/indexer/ffi/cbindgen.toml b/lez/indexer/ffi/cbindgen.toml similarity index 100% rename from indexer/ffi/cbindgen.toml rename to lez/indexer/ffi/cbindgen.toml diff --git a/indexer/ffi/indexer_ffi.h b/lez/indexer/ffi/indexer_ffi.h similarity index 99% rename from indexer/ffi/indexer_ffi.h rename to lez/indexer/ffi/indexer_ffi.h index b2ba41bf..1562eb15 100644 --- a/indexer/ffi/indexer_ffi.h +++ b/lez/indexer/ffi/indexer_ffi.h @@ -194,7 +194,7 @@ typedef struct FfiPublicTransactionBody { } FfiPublicTransactionBody; /** - * Account data structure - C-compatible version of nssa Account. + * Account data structure - C-compatible version of lee Account. * * Note: `balance` and `nonce` are u128 values represented as little-endian * byte arrays since C doesn't have native u128 support. diff --git a/indexer/ffi/src/api/client.rs b/lez/indexer/ffi/src/api/client.rs similarity index 100% rename from indexer/ffi/src/api/client.rs rename to lez/indexer/ffi/src/api/client.rs diff --git a/indexer/ffi/src/api/lifecycle.rs b/lez/indexer/ffi/src/api/lifecycle.rs similarity index 100% rename from indexer/ffi/src/api/lifecycle.rs rename to lez/indexer/ffi/src/api/lifecycle.rs diff --git a/indexer/ffi/src/api/memory.rs b/lez/indexer/ffi/src/api/memory.rs similarity index 100% rename from indexer/ffi/src/api/memory.rs rename to lez/indexer/ffi/src/api/memory.rs diff --git a/indexer/ffi/src/api/mod.rs b/lez/indexer/ffi/src/api/mod.rs similarity index 100% rename from indexer/ffi/src/api/mod.rs rename to lez/indexer/ffi/src/api/mod.rs diff --git a/indexer/ffi/src/api/query.rs b/lez/indexer/ffi/src/api/query.rs similarity index 98% rename from indexer/ffi/src/api/query.rs rename to lez/indexer/ffi/src/api/query.rs index 44951014..f10de598 100644 --- a/indexer/ffi/src/api/query.rs +++ b/lez/indexer/ffi/src/api/query.rs @@ -184,9 +184,8 @@ pub unsafe extern "C" fn query_account( .map_or_else( |_| PointerResult::from_error(OperationStatus::ClientError), |acc| { - let acc_nssa: nssa::Account = - acc.try_into().expect("Source is in blocks, must fit"); - PointerResult::from_value(acc_nssa.into()) + let acc_lee: lee::Account = acc.try_into().expect("Source is in blocks, must fit"); + PointerResult::from_value(acc_lee.into()) }, ) } diff --git a/indexer/ffi/src/api/result.rs b/lez/indexer/ffi/src/api/result.rs similarity index 100% rename from indexer/ffi/src/api/result.rs rename to lez/indexer/ffi/src/api/result.rs diff --git a/indexer/ffi/src/api/types/account.rs b/lez/indexer/ffi/src/api/types/account.rs similarity index 91% rename from indexer/ffi/src/api/types/account.rs rename to lez/indexer/ffi/src/api/types/account.rs index 6c35347f..2309b84b 100644 --- a/indexer/ffi/src/api/types/account.rs +++ b/lez/indexer/ffi/src/api/types/account.rs @@ -2,7 +2,7 @@ use indexer_service_protocol::ProgramId; use crate::api::types::{FfiBytes32, FfiProgramId, FfiU128}; -/// Account data structure - C-compatible version of nssa Account. +/// Account data structure - C-compatible version of lee Account. /// /// Note: `balance` and `nonce` are u128 values represented as little-endian /// byte arrays since C doesn't have native u128 support. @@ -23,15 +23,15 @@ pub struct FfiAccount { // Helper functions to convert between Rust and FFI types -impl From<&nssa::AccountId> for FfiBytes32 { - fn from(id: &nssa::AccountId) -> Self { +impl From<&lee::AccountId> for FfiBytes32 { + fn from(id: &lee::AccountId) -> Self { Self::from_account_id(id) } } -impl From for FfiAccount { - fn from(value: nssa::Account) -> Self { - let nssa::Account { +impl From for FfiAccount { + fn from(value: lee::Account) -> Self { + let lee::Account { program_owner, balance, data, diff --git a/indexer/ffi/src/api/types/block.rs b/lez/indexer/ffi/src/api/types/block.rs similarity index 100% rename from indexer/ffi/src/api/types/block.rs rename to lez/indexer/ffi/src/api/types/block.rs diff --git a/indexer/ffi/src/api/types/mod.rs b/lez/indexer/ffi/src/api/types/mod.rs similarity index 98% rename from indexer/ffi/src/api/types/mod.rs rename to lez/indexer/ffi/src/api/types/mod.rs index 2e7a77ad..b42b014c 100644 --- a/indexer/ffi/src/api/types/mod.rs +++ b/lez/indexer/ffi/src/api/types/mod.rs @@ -48,7 +48,7 @@ impl FfiBytes32 { /// Create from an `AccountId`. #[must_use] - pub const fn from_account_id(id: &nssa::AccountId) -> Self { + pub const fn from_account_id(id: &lee::AccountId) -> Self { Self { data: *id.value() } } } diff --git a/indexer/ffi/src/api/types/transaction.rs b/lez/indexer/ffi/src/api/types/transaction.rs similarity index 99% rename from indexer/ffi/src/api/types/transaction.rs rename to lez/indexer/ffi/src/api/types/transaction.rs index ee3bd01b..ca733ed3 100644 --- a/indexer/ffi/src/api/types/transaction.rs +++ b/lez/indexer/ffi/src/api/types/transaction.rs @@ -267,7 +267,7 @@ impl From for FfiPrivacyPreservingMessage { .into(), public_post_states: public_post_states .into_iter() - .map(|acc_ind| -> nssa::Account { + .map(|acc_ind| -> lee::Account { acc_ind.try_into().expect("Source is in blocks, must fit") }) .map(Into::into) diff --git a/indexer/ffi/src/api/types/vectors.rs b/lez/indexer/ffi/src/api/types/vectors.rs similarity index 100% rename from indexer/ffi/src/api/types/vectors.rs rename to lez/indexer/ffi/src/api/types/vectors.rs diff --git a/indexer/ffi/src/client.rs b/lez/indexer/ffi/src/client.rs similarity index 100% rename from indexer/ffi/src/client.rs rename to lez/indexer/ffi/src/client.rs diff --git a/indexer/ffi/src/errors.rs b/lez/indexer/ffi/src/errors.rs similarity index 100% rename from indexer/ffi/src/errors.rs rename to lez/indexer/ffi/src/errors.rs diff --git a/indexer/ffi/src/indexer.rs b/lez/indexer/ffi/src/indexer.rs similarity index 100% rename from indexer/ffi/src/indexer.rs rename to lez/indexer/ffi/src/indexer.rs diff --git a/indexer/ffi/src/lib.rs b/lez/indexer/ffi/src/lib.rs similarity index 100% rename from indexer/ffi/src/lib.rs rename to lez/indexer/ffi/src/lib.rs diff --git a/indexer/ffi/src/runtime.rs b/lez/indexer/ffi/src/runtime.rs similarity index 100% rename from indexer/ffi/src/runtime.rs rename to lez/indexer/ffi/src/runtime.rs diff --git a/indexer/service/Cargo.toml b/lez/indexer/service/Cargo.toml similarity index 100% rename from indexer/service/Cargo.toml rename to lez/indexer/service/Cargo.toml diff --git a/indexer/service/Dockerfile b/lez/indexer/service/Dockerfile similarity index 100% rename from indexer/service/Dockerfile rename to lez/indexer/service/Dockerfile diff --git a/indexer/service/configs/indexer_config.json b/lez/indexer/service/configs/indexer_config.json similarity index 100% rename from indexer/service/configs/indexer_config.json rename to lez/indexer/service/configs/indexer_config.json diff --git a/indexer/service/docker-compose.yml b/lez/indexer/service/docker-compose.yml similarity index 81% rename from indexer/service/docker-compose.yml rename to lez/indexer/service/docker-compose.yml index b690a180..e9189cfc 100644 --- a/indexer/service/docker-compose.yml +++ b/lez/indexer/service/docker-compose.yml @@ -1,9 +1,9 @@ services: indexer_service: - image: lssa/indexer_service + image: lez/indexer_service build: context: ../.. - dockerfile: indexer/service/Dockerfile + dockerfile: lez/indexer/service/Dockerfile container_name: indexer_service ports: - "8779:8779" diff --git a/indexer/service/protocol/Cargo.toml b/lez/indexer/service/protocol/Cargo.toml similarity index 65% rename from indexer/service/protocol/Cargo.toml rename to lez/indexer/service/protocol/Cargo.toml index 2ee61b74..5a4176f5 100644 --- a/indexer/service/protocol/Cargo.toml +++ b/lez/indexer/service/protocol/Cargo.toml @@ -8,8 +8,8 @@ license = { workspace = true } workspace = true [dependencies] -nssa_core = { workspace = true, optional = true, features = ["host"] } -nssa = { workspace = true, optional = true } +lee_core = { workspace = true, optional = true, features = ["host"] } +lee = { workspace = true, optional = true } common = { workspace = true, optional = true } serde = { workspace = true, features = ["derive"] } @@ -21,5 +21,5 @@ hex.workspace = true anyhow.workspace = true [features] -# Enable conversion to/from NSSA core types -convert = ["dep:nssa_core", "dep:nssa", "dep:common"] +# Enable conversion to/from LEE core types +convert = ["dep:lee_core", "dep:lee", "dep:common"] diff --git a/indexer/service/protocol/src/convert.rs b/lez/indexer/service/protocol/src/convert.rs similarity index 70% rename from indexer/service/protocol/src/convert.rs rename to lez/indexer/service/protocol/src/convert.rs index eb79fa34..cec8b7bb 100644 --- a/indexer/service/protocol/src/convert.rs +++ b/lez/indexer/service/protocol/src/convert.rs @@ -1,6 +1,6 @@ -//! Conversions between `indexer_service_protocol` types and `nssa/nssa_core` types. +//! Conversions between `indexer_service_protocol` types and `lee/lee_core` types. -use nssa_core::account::Nonce; +use lee_core::account::Nonce; use crate::{ Account, AccountId, BedrockStatus, Block, BlockBody, BlockHeader, Ciphertext, Commitment, @@ -26,24 +26,24 @@ impl From for [u32; 8] { } } -impl From for AccountId { - fn from(value: nssa_core::account::AccountId) -> Self { +impl From for AccountId { + fn from(value: lee_core::account::AccountId) -> Self { Self { value: value.into_value(), } } } -impl From for nssa_core::account::AccountId { +impl From for lee_core::account::AccountId { fn from(value: AccountId) -> Self { let AccountId { value } = value; Self::new(value) } } -impl From for Account { - fn from(value: nssa_core::account::Account) -> Self { - let nssa_core::account::Account { +impl From for Account { + fn from(value: lee_core::account::Account) -> Self { + let lee_core::account::Account { program_owner, balance, data, @@ -59,8 +59,8 @@ impl From for Account { } } -impl TryFrom for nssa_core::account::Account { - type Error = nssa_core::account::data::DataTooBigError; +impl TryFrom for lee_core::account::Account { + type Error = lee_core::account::data::DataTooBigError; fn try_from(value: Account) -> Result { let Account { @@ -79,14 +79,14 @@ impl TryFrom for nssa_core::account::Account { } } -impl From for Data { - fn from(value: nssa_core::account::Data) -> Self { +impl From for Data { + fn from(value: lee_core::account::Data) -> Self { Self(value.into_inner()) } } -impl TryFrom for nssa_core::account::Data { - type Error = nssa_core::account::data::DataTooBigError; +impl TryFrom for lee_core::account::Data { + type Error = lee_core::account::data::DataTooBigError; fn try_from(value: Data) -> Result { Self::try_from(value.0) @@ -97,37 +97,37 @@ impl TryFrom for nssa_core::account::Data { // Commitment and Nullifier conversions // ============================================================================ -impl From for Commitment { - fn from(value: nssa_core::Commitment) -> Self { +impl From for Commitment { + fn from(value: lee_core::Commitment) -> Self { Self(value.to_byte_array()) } } -impl From for nssa_core::Commitment { +impl From for lee_core::Commitment { fn from(value: Commitment) -> Self { Self::from_byte_array(value.0) } } -impl From for Nullifier { - fn from(value: nssa_core::Nullifier) -> Self { +impl From for Nullifier { + fn from(value: lee_core::Nullifier) -> Self { Self(value.to_byte_array()) } } -impl From for nssa_core::Nullifier { +impl From for lee_core::Nullifier { fn from(value: Nullifier) -> Self { Self::from_byte_array(value.0) } } -impl From for CommitmentSetDigest { - fn from(value: nssa_core::CommitmentSetDigest) -> Self { +impl From for CommitmentSetDigest { + fn from(value: lee_core::CommitmentSetDigest) -> Self { Self(value) } } -impl From for nssa_core::CommitmentSetDigest { +impl From for lee_core::CommitmentSetDigest { fn from(value: CommitmentSetDigest) -> Self { value.0 } @@ -137,25 +137,25 @@ impl From for nssa_core::CommitmentSetDigest { // Encryption-related conversions // ============================================================================ -impl From for Ciphertext { - fn from(value: nssa_core::encryption::Ciphertext) -> Self { +impl From for Ciphertext { + fn from(value: lee_core::encryption::Ciphertext) -> Self { Self(value.into_inner()) } } -impl From for nssa_core::encryption::Ciphertext { +impl From for lee_core::encryption::Ciphertext { fn from(value: Ciphertext) -> Self { Self::from_inner(value.0) } } -impl From for EphemeralPublicKey { - fn from(value: nssa_core::encryption::EphemeralPublicKey) -> Self { +impl From for EphemeralPublicKey { + fn from(value: lee_core::encryption::EphemeralPublicKey) -> Self { Self(value.0) } } -impl From for nssa_core::encryption::EphemeralPublicKey { +impl From for lee_core::encryption::EphemeralPublicKey { fn from(value: EphemeralPublicKey) -> Self { Self(value.0) } @@ -165,28 +165,28 @@ impl From for nssa_core::encryption::EphemeralPublicKey { // Signature and PublicKey conversions // ============================================================================ -impl From for Signature { - fn from(value: nssa::Signature) -> Self { - let nssa::Signature { value } = value; +impl From for Signature { + fn from(value: lee::Signature) -> Self { + let lee::Signature { value } = value; Self(value) } } -impl From for nssa::Signature { +impl From for lee::Signature { fn from(value: Signature) -> Self { let Signature(sig_value) = value; Self { value: sig_value } } } -impl From for PublicKey { - fn from(value: nssa::PublicKey) -> Self { +impl From for PublicKey { + fn from(value: lee::PublicKey) -> Self { Self(*value.value()) } } -impl TryFrom for nssa::PublicKey { - type Error = nssa::error::NssaError; +impl TryFrom for lee::PublicKey { + type Error = lee::error::LeeError; fn try_from(value: PublicKey) -> Result { Self::try_new(value.0) @@ -197,13 +197,13 @@ impl TryFrom for nssa::PublicKey { // Proof conversions // ============================================================================ -impl From for Proof { - fn from(value: nssa::privacy_preserving_transaction::circuit::Proof) -> Self { +impl From for Proof { + fn from(value: lee::privacy_preserving_transaction::circuit::Proof) -> Self { Self(value.into_inner()) } } -impl From for nssa::privacy_preserving_transaction::circuit::Proof { +impl From for lee::privacy_preserving_transaction::circuit::Proof { fn from(value: Proof) -> Self { Self::from_inner(value.0) } @@ -213,10 +213,10 @@ impl From for nssa::privacy_preserving_transaction::circuit::Proof { // EncryptedAccountData conversions // ============================================================================ -impl From +impl From for EncryptedAccountData { - fn from(value: nssa::privacy_preserving_transaction::message::EncryptedAccountData) -> Self { + fn from(value: lee::privacy_preserving_transaction::message::EncryptedAccountData) -> Self { Self { ciphertext: value.ciphertext.into(), epk: value.epk.into(), @@ -226,7 +226,7 @@ impl From } impl From - for nssa::privacy_preserving_transaction::message::EncryptedAccountData + for lee::privacy_preserving_transaction::message::EncryptedAccountData { fn from(value: EncryptedAccountData) -> Self { Self { @@ -241,9 +241,9 @@ impl From // Transaction Message conversions // ============================================================================ -impl From for PublicMessage { - fn from(value: nssa::public_transaction::Message) -> Self { - let nssa::public_transaction::Message { +impl From for PublicMessage { + fn from(value: lee::public_transaction::Message) -> Self { + let lee::public_transaction::Message { program_id, account_ids, nonces, @@ -258,7 +258,7 @@ impl From for PublicMessage { } } -impl From for nssa::public_transaction::Message { +impl From for lee::public_transaction::Message { fn from(value: PublicMessage) -> Self { let PublicMessage { program_id, @@ -271,16 +271,16 @@ impl From for nssa::public_transaction::Message { account_ids.into_iter().map(Into::into).collect(), nonces .iter() - .map(|x| nssa_core::account::Nonce(*x)) + .map(|x| lee_core::account::Nonce(*x)) .collect(), instruction_data, ) } } -impl From for PrivacyPreservingMessage { - fn from(value: nssa::privacy_preserving_transaction::message::Message) -> Self { - let nssa::privacy_preserving_transaction::message::Message { +impl From for PrivacyPreservingMessage { + fn from(value: lee::privacy_preserving_transaction::message::Message) -> Self { + let lee::privacy_preserving_transaction::message::Message { public_account_ids, nonces, public_post_states, @@ -309,8 +309,8 @@ impl From for PrivacyPre } } -impl TryFrom for nssa::privacy_preserving_transaction::message::Message { - type Error = nssa::error::NssaError; +impl TryFrom for lee::privacy_preserving_transaction::message::Message { + type Error = lee::error::LeeError; fn try_from(value: PrivacyPreservingMessage) -> Result { let PrivacyPreservingMessage { @@ -327,13 +327,13 @@ impl TryFrom for nssa::privacy_preserving_transaction: public_account_ids: public_account_ids.into_iter().map(Into::into).collect(), nonces: nonces .iter() - .map(|x| nssa_core::account::Nonce(*x)) + .map(|x| lee_core::account::Nonce(*x)) .collect(), public_post_states: public_post_states .into_iter() .map(TryInto::try_into) .collect::, _>>() - .map_err(|e| nssa::error::NssaError::InvalidInput(format!("{e}")))?, + .map_err(|e| lee::error::LeeError::InvalidInput(format!("{e}")))?, encrypted_private_post_states: encrypted_private_post_states .into_iter() .map(Into::into) @@ -345,23 +345,23 @@ impl TryFrom for nssa::privacy_preserving_transaction: .collect(), block_validity_window: block_validity_window .try_into() - .map_err(|e| nssa::error::NssaError::InvalidInput(format!("{e}")))?, + .map_err(|e| lee::error::LeeError::InvalidInput(format!("{e}")))?, timestamp_validity_window: timestamp_validity_window .try_into() - .map_err(|e| nssa::error::NssaError::InvalidInput(format!("{e}")))?, + .map_err(|e| lee::error::LeeError::InvalidInput(format!("{e}")))?, }) } } -impl From for ProgramDeploymentMessage { - fn from(value: nssa::program_deployment_transaction::Message) -> Self { +impl From for ProgramDeploymentMessage { + fn from(value: lee::program_deployment_transaction::Message) -> Self { Self { bytecode: value.into_bytecode(), } } } -impl From for nssa::program_deployment_transaction::Message { +impl From for lee::program_deployment_transaction::Message { fn from(value: ProgramDeploymentMessage) -> Self { let ProgramDeploymentMessage { bytecode } = value; Self::new(bytecode) @@ -372,8 +372,8 @@ impl From for nssa::program_deployment_transaction::Me // WitnessSet conversions // ============================================================================ -impl From for WitnessSet { - fn from(value: nssa::public_transaction::WitnessSet) -> Self { +impl From for WitnessSet { + fn from(value: lee::public_transaction::WitnessSet) -> Self { Self { signatures_and_public_keys: value .signatures_and_public_keys() @@ -385,8 +385,8 @@ impl From for WitnessSet { } } -impl From for WitnessSet { - fn from(value: nssa::privacy_preserving_transaction::witness_set::WitnessSet) -> Self { +impl From for WitnessSet { + fn from(value: lee::privacy_preserving_transaction::witness_set::WitnessSet) -> Self { let (sigs_and_pks, proof) = value.into_raw_parts(); Self { signatures_and_public_keys: sigs_and_pks @@ -398,8 +398,8 @@ impl From for Wit } } -impl TryFrom for nssa::privacy_preserving_transaction::witness_set::WitnessSet { - type Error = nssa::error::NssaError; +impl TryFrom for lee::privacy_preserving_transaction::witness_set::WitnessSet { + type Error = lee::error::LeeError; fn try_from(value: WitnessSet) -> Result { let WitnessSet { @@ -415,7 +415,7 @@ impl TryFrom for nssa::privacy_preserving_transaction::witness_set:: signatures_and_public_keys, proof .map(Into::into) - .ok_or_else(|| nssa::error::NssaError::InvalidInput("Missing proof".to_owned()))?, + .ok_or_else(|| lee::error::LeeError::InvalidInput("Missing proof".to_owned()))?, )) } } @@ -424,10 +424,10 @@ impl TryFrom for nssa::privacy_preserving_transaction::witness_set:: // Transaction conversions // ============================================================================ -impl From for PublicTransaction { - fn from(value: nssa::PublicTransaction) -> Self { +impl From for PublicTransaction { + fn from(value: lee::PublicTransaction) -> Self { let hash = HashType(value.hash()); - let nssa::PublicTransaction { + let lee::PublicTransaction { message, witness_set, } = value; @@ -440,8 +440,8 @@ impl From for PublicTransaction { } } -impl TryFrom for nssa::PublicTransaction { - type Error = nssa::error::NssaError; +impl TryFrom for lee::PublicTransaction { + type Error = lee::error::LeeError; fn try_from(value: PublicTransaction) -> Result { let PublicTransaction { @@ -456,7 +456,7 @@ impl TryFrom for nssa::PublicTransaction { Ok(Self::new( message.into(), - nssa::public_transaction::WitnessSet::from_raw_parts( + lee::public_transaction::WitnessSet::from_raw_parts( signatures_and_public_keys .into_iter() .map(|(sig, pk)| Ok((sig.into(), pk.try_into()?))) @@ -466,10 +466,10 @@ impl TryFrom for nssa::PublicTransaction { } } -impl From for PrivacyPreservingTransaction { - fn from(value: nssa::PrivacyPreservingTransaction) -> Self { +impl From for PrivacyPreservingTransaction { + fn from(value: lee::PrivacyPreservingTransaction) -> Self { let hash = HashType(value.hash()); - let nssa::PrivacyPreservingTransaction { + let lee::PrivacyPreservingTransaction { message, witness_set, } = value; @@ -482,8 +482,8 @@ impl From for PrivacyPreservingTransaction { } } -impl TryFrom for nssa::PrivacyPreservingTransaction { - type Error = nssa::error::NssaError; +impl TryFrom for lee::PrivacyPreservingTransaction { + type Error = lee::error::LeeError; fn try_from(value: PrivacyPreservingTransaction) -> Result { let PrivacyPreservingTransaction { @@ -496,10 +496,10 @@ impl TryFrom for nssa::PrivacyPreservingTransactio } } -impl From for ProgramDeploymentTransaction { - fn from(value: nssa::ProgramDeploymentTransaction) -> Self { +impl From for ProgramDeploymentTransaction { + fn from(value: lee::ProgramDeploymentTransaction) -> Self { let hash = HashType(value.hash()); - let nssa::ProgramDeploymentTransaction { message } = value; + let lee::ProgramDeploymentTransaction { message } = value; Self { hash, @@ -508,29 +508,29 @@ impl From for ProgramDeploymentTransaction { } } -impl From for nssa::ProgramDeploymentTransaction { +impl From for lee::ProgramDeploymentTransaction { fn from(value: ProgramDeploymentTransaction) -> Self { let ProgramDeploymentTransaction { hash: _, message } = value; Self::new(message.into()) } } -impl From for Transaction { - fn from(value: common::transaction::NSSATransaction) -> Self { +impl From for Transaction { + fn from(value: common::transaction::LeeTransaction) -> Self { match value { - common::transaction::NSSATransaction::Public(tx) => Self::Public(tx.into()), - common::transaction::NSSATransaction::PrivacyPreserving(tx) => { + common::transaction::LeeTransaction::Public(tx) => Self::Public(tx.into()), + common::transaction::LeeTransaction::PrivacyPreserving(tx) => { Self::PrivacyPreserving(tx.into()) } - common::transaction::NSSATransaction::ProgramDeployment(tx) => { + common::transaction::LeeTransaction::ProgramDeployment(tx) => { Self::ProgramDeployment(tx.into()) } } } } -impl TryFrom for common::transaction::NSSATransaction { - type Error = nssa::error::NssaError; +impl TryFrom for common::transaction::LeeTransaction { + type Error = lee::error::LeeError; fn try_from(value: Transaction) -> Result { match value { @@ -565,7 +565,7 @@ impl From for BlockHeader { } impl TryFrom for common::block::BlockHeader { - type Error = nssa::error::NssaError; + type Error = lee::error::LeeError; fn try_from(value: BlockHeader) -> Result { let BlockHeader { @@ -592,11 +592,11 @@ impl From for BlockBody { let transactions = transactions .into_iter() .map(|tx| match tx { - common::transaction::NSSATransaction::Public(tx) => Transaction::Public(tx.into()), - common::transaction::NSSATransaction::PrivacyPreserving(tx) => { + common::transaction::LeeTransaction::Public(tx) => Transaction::Public(tx.into()), + common::transaction::LeeTransaction::PrivacyPreserving(tx) => { Transaction::PrivacyPreserving(tx.into()) } - common::transaction::NSSATransaction::ProgramDeployment(tx) => { + common::transaction::LeeTransaction::ProgramDeployment(tx) => { Transaction::ProgramDeployment(tx.into()) } }) @@ -607,7 +607,7 @@ impl From for BlockBody { } impl TryFrom for common::block::BlockBody { - type Error = nssa::error::NssaError; + type Error = lee::error::LeeError; fn try_from(value: BlockBody) -> Result { let BlockBody { transactions } = value; @@ -615,8 +615,8 @@ impl TryFrom for common::block::BlockBody { let transactions = transactions .into_iter() .map(|tx| { - let nssa_tx: common::transaction::NSSATransaction = tx.try_into()?; - Ok::<_, nssa::error::NssaError>(nssa_tx) + let lee_tx: common::transaction::LeeTransaction = tx.try_into()?; + Ok::<_, lee::error::LeeError>(lee_tx) }) .collect::, _>>()?; @@ -643,7 +643,7 @@ impl From for Block { } impl TryFrom for common::block::Block { - type Error = nssa::error::NssaError; + type Error = lee::error::LeeError; fn try_from(value: Block) -> Result { let Block { @@ -698,14 +698,14 @@ impl From for common::HashType { // ValidityWindow conversions // ============================================================================ -impl From> for ValidityWindow { - fn from(value: nssa_core::program::ValidityWindow) -> Self { +impl From> for ValidityWindow { + fn from(value: lee_core::program::ValidityWindow) -> Self { Self((value.start(), value.end())) } } -impl TryFrom for nssa_core::program::ValidityWindow { - type Error = nssa_core::program::InvalidWindow; +impl TryFrom for lee_core::program::ValidityWindow { + type Error = lee_core::program::InvalidWindow; fn try_from(value: ValidityWindow) -> Result { value.0.try_into() diff --git a/indexer/service/protocol/src/lib.rs b/lez/indexer/service/protocol/src/lib.rs similarity index 99% rename from indexer/service/protocol/src/lib.rs rename to lez/indexer/service/protocol/src/lib.rs index d554267e..0d94167d 100644 --- a/indexer/service/protocol/src/lib.rs +++ b/lez/indexer/service/protocol/src/lib.rs @@ -1,6 +1,6 @@ //! This crate defines the protocol types used by the indexer service. //! -//! Currently it mostly mimics types from `nssa_core`, but it's important to have a separate crate +//! Currently it mostly mimics types from `lee_core`, but it's important to have a separate crate //! to define a stable interface for the indexer service RPCs which evolves in its own way. use std::{fmt::Display, str::FromStr}; diff --git a/indexer/service/rpc/Cargo.toml b/lez/indexer/service/rpc/Cargo.toml similarity index 100% rename from indexer/service/rpc/Cargo.toml rename to lez/indexer/service/rpc/Cargo.toml diff --git a/indexer/service/rpc/src/lib.rs b/lez/indexer/service/rpc/src/lib.rs similarity index 100% rename from indexer/service/rpc/src/lib.rs rename to lez/indexer/service/rpc/src/lib.rs diff --git a/indexer/service/src/lib.rs b/lez/indexer/service/src/lib.rs similarity index 100% rename from indexer/service/src/lib.rs rename to lez/indexer/service/src/lib.rs diff --git a/indexer/service/src/main.rs b/lez/indexer/service/src/main.rs similarity index 100% rename from indexer/service/src/main.rs rename to lez/indexer/service/src/main.rs diff --git a/indexer/service/src/mock_service.rs b/lez/indexer/service/src/mock_service.rs similarity index 100% rename from indexer/service/src/mock_service.rs rename to lez/indexer/service/src/mock_service.rs diff --git a/indexer/service/src/service.rs b/lez/indexer/service/src/service.rs similarity index 100% rename from indexer/service/src/service.rs rename to lez/indexer/service/src/service.rs diff --git a/keycard_wallet/Cargo.toml b/lez/keycard_wallet/Cargo.toml similarity index 92% rename from keycard_wallet/Cargo.toml rename to lez/keycard_wallet/Cargo.toml index 6a9d0668..4abff1f1 100644 --- a/keycard_wallet/Cargo.toml +++ b/lez/keycard_wallet/Cargo.toml @@ -8,7 +8,7 @@ license = { workspace = true } workspace = true [dependencies] -nssa.workspace = true +lee.workspace = true pyo3.workspace = true log.workspace = true serde = { workspace = true, features = ["derive"] } diff --git a/keycard_wallet/keycard_applets/LEE_keycard.cap b/lez/keycard_wallet/keycard_applets/LEE_keycard.cap similarity index 100% rename from keycard_wallet/keycard_applets/LEE_keycard.cap rename to lez/keycard_wallet/keycard_applets/LEE_keycard.cap diff --git a/keycard_wallet/keycard_applets/math.cap b/lez/keycard_wallet/keycard_applets/math.cap similarity index 100% rename from keycard_wallet/keycard_applets/math.cap rename to lez/keycard_wallet/keycard_applets/math.cap diff --git a/keycard_wallet/python/keycard_wallet.py b/lez/keycard_wallet/python/keycard_wallet.py similarity index 100% rename from keycard_wallet/python/keycard_wallet.py rename to lez/keycard_wallet/python/keycard_wallet.py diff --git a/keycard_wallet/src/lib.rs b/lez/keycard_wallet/src/lib.rs similarity index 98% rename from keycard_wallet/src/lib.rs rename to lez/keycard_wallet/src/lib.rs index a27d99fd..1f009900 100644 --- a/keycard_wallet/src/lib.rs +++ b/lez/keycard_wallet/src/lib.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use nssa::{AccountId, PublicKey, Signature}; +use lee::{AccountId, PublicKey, Signature}; use pyo3::{prelude::*, types::PyAny}; use serde::{Deserialize, Serialize}; use zeroize::Zeroizing; @@ -269,11 +269,11 @@ impl KeycardWallet { } fn pairing_file_path() -> Option { - let home = std::env::var("NSSA_WALLET_HOME_DIR") + let home = std::env::var("LEE_WALLET_HOME_DIR") .map(PathBuf::from) .or_else(|_| { std::env::home_dir() - .map(|h| h.join(".nssa").join("wallet")) + .map(|h| h.join(".lee").join("wallet")) .ok_or(()) }) .ok()?; diff --git a/keycard_wallet/src/python_path.rs b/lez/keycard_wallet/src/python_path.rs similarity index 96% rename from keycard_wallet/src/python_path.rs rename to lez/keycard_wallet/src/python_path.rs index 8251f7a3..5261d7b7 100644 --- a/keycard_wallet/src/python_path.rs +++ b/lez/keycard_wallet/src/python_path.rs @@ -52,7 +52,7 @@ pub fn add_python_path(py: Python<'_>) -> PyResult<()> { // Avoid duplicating the path let already_present = sys_path .iter() - .any(|p| p.extract::<&str>().map(|s| s == path_str).unwrap_or(false)); + .any(|p| p.extract::<&str>().is_ok_and(|s| s == path_str)); if !already_present { sys_path.insert(0, path_str)?; diff --git a/keycard_wallet/tests/force_unpower.py b/lez/keycard_wallet/tests/force_unpower.py similarity index 100% rename from keycard_wallet/tests/force_unpower.py rename to lez/keycard_wallet/tests/force_unpower.py diff --git a/keycard_wallet/tests/keycard_power_recovery_tests.sh b/lez/keycard_wallet/tests/keycard_power_recovery_tests.sh similarity index 100% rename from keycard_wallet/tests/keycard_power_recovery_tests.sh rename to lez/keycard_wallet/tests/keycard_power_recovery_tests.sh diff --git a/keycard_wallet/tests/keycard_test_3.sh b/lez/keycard_wallet/tests/keycard_test_3.sh similarity index 100% rename from keycard_wallet/tests/keycard_test_3.sh rename to lez/keycard_wallet/tests/keycard_test_3.sh diff --git a/keycard_wallet/tests/keycard_tests.sh b/lez/keycard_wallet/tests/keycard_tests.sh similarity index 100% rename from keycard_wallet/tests/keycard_tests.sh rename to lez/keycard_wallet/tests/keycard_tests.sh diff --git a/keycard_wallet/tests/keycard_tests_2.sh b/lez/keycard_wallet/tests/keycard_tests_2.sh similarity index 100% rename from keycard_wallet/tests/keycard_tests_2.sh rename to lez/keycard_wallet/tests/keycard_tests_2.sh diff --git a/keycard_wallet/wallet_with_keycard.sh b/lez/keycard_wallet/wallet_with_keycard.sh similarity index 61% rename from keycard_wallet/wallet_with_keycard.sh rename to lez/keycard_wallet/wallet_with_keycard.sh index bcd87bd3..7a43bb57 100755 --- a/keycard_wallet/wallet_with_keycard.sh +++ b/lez/keycard_wallet/wallet_with_keycard.sh @@ -1,12 +1,12 @@ #!/bin/bash -cargo install --path wallet --force +cargo install --path lez/wallet --force # Install appropriate version of `keycard-py`. -git clone --branch lee-schnorr --single-branch https://github.com/bitgamma/keycard-py.git keycard_wallet/python/keycard-py +git clone --branch lee-schnorr --single-branch https://github.com/bitgamma/keycard-py.git lez/keycard_wallet/python/keycard-py # Set up virtual environment. python3 -m venv venv source venv/bin/activate pip install pyscard mnemonic ecdsa pyaes -pip install -e keycard_wallet/python/keycard-py \ No newline at end of file +pip install -e lez/keycard_wallet/python/keycard-py \ No newline at end of file diff --git a/mempool/Cargo.toml b/lez/mempool/Cargo.toml similarity index 100% rename from mempool/Cargo.toml rename to lez/mempool/Cargo.toml diff --git a/mempool/src/lib.rs b/lez/mempool/src/lib.rs similarity index 96% rename from mempool/src/lib.rs rename to lez/mempool/src/lib.rs index 3bf4ac2a..1b36eaf7 100644 --- a/mempool/src/lib.rs +++ b/lez/mempool/src/lib.rs @@ -48,6 +48,14 @@ pub struct MemPoolHandle { sender: Sender, } +impl Clone for MemPoolHandle { + fn clone(&self) -> Self { + Self { + sender: self.sender.clone(), + } + } +} + impl MemPoolHandle { const fn new(sender: Sender) -> Self { Self { sender } diff --git a/sequencer/core/Cargo.toml b/lez/sequencer/core/Cargo.toml similarity index 84% rename from sequencer/core/Cargo.toml rename to lez/sequencer/core/Cargo.toml index 5f74fbde..f7296f42 100644 --- a/sequencer/core/Cargo.toml +++ b/lez/sequencer/core/Cargo.toml @@ -8,14 +8,15 @@ license = { workspace = true } workspace = true [dependencies] -nssa.workspace = true -nssa_core.workspace = true +lee.workspace = true +lee_core.workspace = true common.workspace = true storage.workspace = true mempool.workspace = true logos-blockchain-zone-sdk.workspace = true testnet_initial_state.workspace = true faucet_core.workspace = true +bridge_core.workspace = true vault_core.workspace = true anyhow.workspace = true @@ -31,7 +32,9 @@ logos-blockchain-core.workspace = true rand.workspace = true borsh.workspace = true bytesize.workspace = true +hex.workspace = true url.workspace = true +risc0-zkvm.workspace = true [features] default = [] @@ -42,4 +45,4 @@ mock = [] [dev-dependencies] futures.workspace = true test_program_methods.workspace = true -nssa = { workspace = true, features = ["test-utils"] } +lee = { workspace = true, features = ["test-utils"] } diff --git a/sequencer/core/src/block_publisher.rs b/lez/sequencer/core/src/block_publisher.rs similarity index 61% rename from sequencer/core/src/block_publisher.rs rename to lez/sequencer/core/src/block_publisher.rs index 9f4c8235..f07a47c6 100644 --- a/sequencer/core/src/block_publisher.rs +++ b/lez/sequencer/core/src/block_publisher.rs @@ -1,6 +1,6 @@ -use std::{sync::Arc, time::Duration}; +use std::{pin::Pin, sync::Arc, time::Duration}; -use anyhow::{Context as _, Result, anyhow}; +use anyhow::{Context as _, Result}; use common::block::Block; use log::warn; pub use logos_blockchain_core::mantle::ops::channel::MsgId; @@ -10,7 +10,7 @@ use logos_blockchain_zone_sdk::{ CommonHttpClient, adapter::NodeHttpClient, sequencer::{Event, SequencerConfig as ZoneSdkSequencerConfig, SequencerHandle, ZoneSequencer}, - state::InscriptionInfo, + state::{DepositInfo, FinalizedOp, InscriptionInfo}, }; use tokio::task::JoinHandle; @@ -18,12 +18,16 @@ use crate::config::BedrockConfig; /// Sink for `Event::Published` checkpoints emitted by the drive task. /// Caller is responsible for persistence (e.g. writing to rocksdb). -pub type CheckpointSink = Box; +pub type CheckpointSink = Box; /// Sink for finalized L2 block ids derived from `Event::TxsFinalized` and /// `Event::FinalizedInscriptions`. Caller is responsible for cleanup /// (e.g. marking pending blocks as finalized in storage). -pub type FinalizedBlockSink = Box; +pub type FinalizedBlockSink = Box; + +/// Sink for finalized Bedrock deposit events. +pub type OnDepositEventSink = + Box Pin + Send>> + Send + 'static>; #[expect(async_fn_in_trait, reason = "We don't care about Send/Sync here")] pub trait BlockPublisherTrait: Clone { @@ -34,6 +38,7 @@ pub trait BlockPublisherTrait: Clone { initial_checkpoint: Option, on_checkpoint: CheckpointSink, on_finalized_block: FinalizedBlockSink, + on_deposit_event: OnDepositEventSink, ) -> Result; /// Fire-and-forget publish. Zone-sdk drives the actual submission and @@ -65,6 +70,7 @@ impl BlockPublisherTrait for ZoneSdkPublisher { initial_checkpoint: Option, on_checkpoint: CheckpointSink, on_finalized_block: FinalizedBlockSink, + on_deposit_event: OnDepositEventSink, ) -> Result { let basic_auth = config.auth.clone().map(Into::into); let node = NodeHttpClient::new(CommonHttpClient::new(basic_auth), config.node_url.clone()); @@ -88,14 +94,27 @@ impl BlockPublisherTrait for ZoneSdkPublisher { continue; }; match event { - Event::Published { checkpoint, .. } => on_checkpoint(checkpoint), - Event::TxsFinalized { inscriptions, .. } - | Event::FinalizedInscriptions { inscriptions } => { - if let Some(max_block_id) = max_block_id_from_inscriptions(&inscriptions) { - on_finalized_block(max_block_id); + Event::Checkpoint { checkpoint } => on_checkpoint(checkpoint), + Event::TxsFinalized { items } => { + for op in items.into_iter().flat_map(|item| item.ops) { + match op { + FinalizedOp::Inscription(inscription) => { + if let Some(block_id) = block_id_from_inscription(&inscription) + { + on_finalized_block(block_id); + } + } + FinalizedOp::Deposit(deposit) => { + on_deposit_event(deposit).await; + } + FinalizedOp::Withdraw(_) => {} + } } } - Event::ChannelUpdate { .. } | Event::Ready => {} + Event::ChannelUpdate { .. } + | Event::Published { .. } + | Event::Readiness { .. } + | Event::TurnNotification { .. } => {} } } }); @@ -110,27 +129,26 @@ impl BlockPublisherTrait for ZoneSdkPublisher { async fn publish_block(&self, block: &Block) -> Result<()> { let data = borsh::to_vec(block).context("Failed to serialize block")?; + let data_bounded = data + .try_into() + .context("Block data exceeds maximum allowed size")?; + self.handle - .publish_message(data) + .publish_message(data_bounded) .await - .map_err(|e| anyhow!("zone-sdk publish failed: {e}"))?; + .context("Failed to publish block")?; + Ok(()) } } -/// Deserialize each inscription payload as a `Block` and return the highest -/// `block_id`. Bad payloads are logged and skipped. -fn max_block_id_from_inscriptions(inscriptions: &[InscriptionInfo]) -> Option { - inscriptions - .iter() - .filter_map( - |inscription| match borsh::from_slice::(&inscription.payload) { - Ok(block) => Some(block.header.block_id), - Err(err) => { - warn!("Failed to deserialize finalized inscription as Block: {err:#}"); - None - } - }, - ) - .max() +/// Deserialize inscription payload as a `Block` and return it's`block_id`. +/// Bad payloads are logged and skipped. +fn block_id_from_inscription(inscription: &InscriptionInfo) -> Option { + borsh::from_slice::(&inscription.payload) + .inspect_err(|err| { + warn!("Failed to deserialize block from inscription: {err:?}"); + }) + .ok() + .map(|block| block.header.block_id) } diff --git a/sequencer/core/src/block_store.rs b/lez/sequencer/core/src/block_store.rs similarity index 91% rename from sequencer/core/src/block_store.rs rename to lez/sequencer/core/src/block_store.rs index ada6d306..97a23848 100644 --- a/sequencer/core/src/block_store.rs +++ b/lez/sequencer/core/src/block_store.rs @@ -4,25 +4,25 @@ use anyhow::{Context as _, Result}; use common::{ HashType, block::{Block, BlockMeta, MantleMsgId}, - transaction::NSSATransaction, + transaction::LeeTransaction, }; +use lee::V03State; use log::info; use logos_blockchain_zone_sdk::sequencer::SequencerCheckpoint; -use nssa::V03State; pub use storage::DbResult; -use storage::sequencer::RocksDBIO; +use storage::sequencer::{RocksDBIO, sequencer_cells::PendingDepositEventRecord}; pub struct SequencerStore { dbio: Arc, // TODO: Consider adding the hashmap to the database for faster recovery. tx_hash_to_block_map: HashMap, genesis_id: u64, - signing_key: nssa::PrivateKey, + signing_key: lee::PrivateKey, } impl SequencerStore { /// Open existing database at the given location. Fails if no database is found. - pub fn open_db(location: &Path, signing_key: nssa::PrivateKey) -> DbResult { + pub fn open_db(location: &Path, signing_key: lee::PrivateKey) -> DbResult { let dbio = Arc::new(RocksDBIO::open(location)?); let genesis_id = dbio.get_meta_first_block_in_db()?; let last_id = dbio.latest_block_meta()?.id; @@ -58,7 +58,7 @@ impl SequencerStore { genesis_block: &Block, genesis_msg_id: MantleMsgId, genesis_state: &V03State, - signing_key: nssa::PrivateKey, + signing_key: lee::PrivateKey, ) -> DbResult { let dbio = Arc::new(RocksDBIO::create( location, @@ -99,7 +99,7 @@ impl SequencerStore { /// Returns the transaction corresponding to the given hash, if it exists in the blockchain. #[must_use] - pub fn get_transaction_by_hash(&self, hash: HashType) -> Option { + pub fn get_transaction_by_hash(&self, hash: HashType) -> Option { let block_id = *self.tx_hash_to_block_map.get(&hash)?; let block = self .get_block_at_id(block_id) @@ -126,7 +126,7 @@ impl SequencerStore { } #[must_use] - pub const fn signing_key(&self) -> &nssa::PrivateKey { + pub const fn signing_key(&self) -> &lee::PrivateKey { &self.signing_key } @@ -146,8 +146,8 @@ impl SequencerStore { Ok(()) } - pub fn get_nssa_state(&self) -> DbResult { - self.dbio.get_nssa_state() + pub fn get_lee_state(&self) -> DbResult { + self.dbio.get_lee_state() } pub fn get_zone_checkpoint(&self) -> Result> { @@ -165,6 +165,27 @@ impl SequencerStore { self.dbio.put_zone_sdk_checkpoint_bytes(&bytes)?; Ok(()) } + + pub fn get_unfulfilled_deposit_events(&self) -> DbResult> { + self.dbio.get_pending_deposit_events() + } + + pub fn mark_unfulfilled_deposit_events_submitted( + &self, + deposit_op_ids: &[HashType], + submitted_block_id: u64, + ) -> DbResult { + self.dbio + .mark_pending_deposit_events_submitted(deposit_op_ids, submitted_block_id) + } + + pub fn remove_fulfilled_unfulfilled_deposit_events_up_to_block( + &self, + finalized_block_id: u64, + ) -> DbResult { + self.dbio + .remove_fulfilled_pending_deposit_events_up_to_block(finalized_block_id) + } } pub(crate) fn block_to_transactions_map(block: &Block) -> HashMap { diff --git a/sequencer/core/src/config.rs b/lez/sequencer/core/src/config.rs similarity index 96% rename from sequencer/core/src/config.rs rename to lez/sequencer/core/src/config.rs index 371ebc89..b445bcd5 100644 --- a/sequencer/core/src/config.rs +++ b/lez/sequencer/core/src/config.rs @@ -9,8 +9,8 @@ use anyhow::Result; use bytesize::ByteSize; use common::config::BasicAuth; use humantime_serde; +use lee::AccountId; use logos_blockchain_core::mantle::ops::channel::ChannelId; -use nssa::AccountId; use serde::{Deserialize, Serialize}; use url::Url; @@ -22,6 +22,9 @@ pub enum GenesisAction { account_id: AccountId, balance: u128, }, + SupplyBridgeAccount { + balance: u128, + }, } // TODO: Provide default values diff --git a/sequencer/core/src/lib.rs b/lez/sequencer/core/src/lib.rs similarity index 63% rename from sequencer/core/src/lib.rs rename to lez/sequencer/core/src/lib.rs index c6606145..0f836c00 100644 --- a/sequencer/core/src/lib.rs +++ b/lez/sequencer/core/src/lib.rs @@ -1,20 +1,22 @@ -use std::{path::Path, time::Instant}; +use std::{path::Path, sync::Arc, time::Instant}; use anyhow::{Context as _, Result, anyhow}; +use borsh::BorshDeserialize; use common::{ HashType, block::{BedrockStatus, Block, HashableBlockData}, - transaction::{NSSATransaction, clock_invocation}, + transaction::{LeeTransaction, clock_invocation}, }; use config::{GenesisAction, SequencerConfig}; +use lee::{AccountId, PublicTransaction, program::Program, public_transaction::Message}; +use lee_core::GENESIS_BLOCK_ID; use log::{error, info, warn}; use logos_blockchain_key_management_system_service::keys::{ED25519_SECRET_KEY_SIZE, Ed25519Key}; use mempool::{MemPool, MemPoolHandle}; #[cfg(feature = "mock")] pub use mock::SequencerCoreWithMockClients; -use nssa::{AccountId, PublicTransaction, program::Program, public_transaction::Message}; -use nssa_core::GENESIS_BLOCK_ID; pub use storage::error::DbError; +use storage::sequencer::sequencer_cells::PendingDepositEventRecord; use crate::{ block_publisher::{BlockPublisherTrait, ZoneSdkPublisher}, @@ -28,10 +30,29 @@ pub mod config; #[cfg(feature = "mock")] pub mod mock; +/// The origin of a transaction. +pub enum TransactionOrigin { + /// Basic transactions submitted by users via RPC. + User, + /// Transactions generated by the sequencer itself. + Sequencer, +} + +#[derive(Clone, Debug, BorshDeserialize)] +struct DepositMetadata { + recipient_id: lee::AccountId, +} + +impl DepositMetadata { + fn decode(bytes: &[u8]) -> Result { + Self::try_from_slice(bytes) + } +} + pub struct SequencerCore { - state: nssa::V03State, + state: lee::V03State, store: SequencerStore, - mempool: MemPool, + mempool: MemPool<(TransactionOrigin, LeeTransaction)>, sequencer_config: SequencerConfig, chain_height: u64, block_publisher: BP, @@ -45,8 +66,8 @@ impl SequencerCore { /// initializing its state with the accounts defined in the configuration file. pub async fn start_from_config( config: SequencerConfig, - ) -> (Self, MemPoolHandle) { - let signing_key = nssa::PrivateKey::try_new(config.signing_key).unwrap(); + ) -> (Self, MemPoolHandle<(TransactionOrigin, LeeTransaction)>) { + let signing_key = lee::PrivateKey::try_new(config.signing_key).unwrap(); let bedrock_signing_key = load_or_create_signing_key(&config.home.join("bedrock_signing_key")) @@ -62,7 +83,7 @@ impl SequencerCore { ) }); let state = store - .get_nssa_state() + .get_lee_state() .expect("Failed to read state from store"); let genesis_block = store .get_block_at_id(store.genesis_id()) @@ -127,9 +148,86 @@ impl SequencerCore { let dbio_for_finalized = store.dbio(); let on_finalized_block: block_publisher::FinalizedBlockSink = Box::new(move |block_id| { + // NOTE: Theoretically Zone SDK may report finalization happening multiple times for the + // same block. In practice this is very unlikely to happen. For that to + // happen Sequencer should crash between receiving Finalized and Checkpoint events while + // these events happen very fast (because Checkpoints are generated by Zone SDK + // locally). + if let Err(err) = dbio_for_finalized.clean_pending_blocks_up_to(block_id) { error!("Failed to mark pending blocks finalized up to {block_id}: {err:#}"); } + + match dbio_for_finalized.remove_fulfilled_pending_deposit_events_up_to_block(block_id) { + Ok(0) => {} + Ok(removed) => { + info!( + "Removed {removed} fulfilled pending deposit events up to finalized block {block_id}" + ); + } + Err(err) => { + error!( + "Failed to remove fulfilled pending deposit events up to block {block_id}: {err:#}" + ); + } + } + }); + + let (mempool, mempool_handle) = MemPool::new(config.mempool_max_size); + + replay_unfulfilled_deposit_events(&store, mempool_handle.clone()); + + let mempool_handle_for_deposit = mempool_handle.clone(); + let dbio_for_deposit = store.dbio(); + let on_deposit_event: block_publisher::OnDepositEventSink = Box::new(move |deposit| { + // NOTE: Theoretically Zone SDK may report multiple identical deposits. In practice this + // is very unlikely to happen. For that to happen Sequencer should crash + // between receiving Deposit and Checkpoint events while these events happen + // very fast (because Checkpoints are generated by Zone SDK locally). + + let dbio_for_deposit = Arc::clone(&dbio_for_deposit); + let mempool_handle_for_deposit = mempool_handle_for_deposit.clone(); + Box::pin(async move { + let id_hex = hex::encode(deposit.op_id); + info!("Observed Bedrock Deposit event with id: {id_hex}"); + + let event_record = pending_deposit_event_record(&deposit); + + match dbio_for_deposit.add_pending_deposit_event(event_record.clone()) { + Ok(true) => {} + Ok(false) => { + info!( + "Deposit event {id_hex} already persisted as unfulfilled, skipping duplicate enqueue", + ); + return; + } + Err(err) => { + error!( + "Failed to persist unfulfilled deposit event {id_hex} before enqueue: {err:#}. Deposit will be lost.", + ); + return; + } + } + + let tx = match build_bridge_deposit_tx_from_event(&event_record) { + Ok(tx) => tx, + Err(err) => { + error!( + "Failed to build transaction from Bedrock deposit event {id_hex}: {err:#}. Deposit will be lost.", + ); + return; + } + }; + + if let Err(err) = mempool_handle_for_deposit + .push((TransactionOrigin::Sequencer, tx)) + .await + { + error!( + "Failed to queue sequencer transaction built from finalized Bedrock event: {err:#}. Deposit will be lost." + ); + } + }) }); let block_publisher = BP::new( @@ -139,6 +237,7 @@ impl SequencerCore { initial_checkpoint, on_checkpoint, on_finalized_block, + on_deposit_event, ) .await .expect("Failed to initialize Block Publisher"); @@ -147,12 +246,13 @@ impl SequencerCore { // genesis block so the indexer can find the channel start. After the // first publish, zone-sdk's checkpoint persistence covers further // restarts. - if is_fresh_start && let Err(err) = block_publisher.publish_block(&genesis_block).await { - error!("Failed to publish genesis block: {err:#}"); + if is_fresh_start { + block_publisher + .publish_block(&genesis_block) + .await + .expect("Failed to publish genesis block"); } - let (mempool, mempool_handle) = MemPool::new(config.mempool_max_size); - let sequencer_core = Self { state, store, @@ -167,30 +267,47 @@ impl SequencerCore { /// Produces a new block from mempool transactions and publishes it via zone-sdk. pub async fn produce_new_block(&mut self) -> Result { - let block = self + let block_with_meta = self .build_block_from_mempool() .context("Failed to build block from mempool transactions")?; + let BlockWithMeta { + block, + deposit_event_ids, + } = block_with_meta; // TODO: Remove msg_id from store.update — it is no longer needed now that // zone-sdk manages L1 settlement state via its own checkpoint. let placeholder_msg_id = [0_u8; 32]; - if let Err(err) = self.block_publisher.publish_block(&block).await { - error!("Failed to publish block to Bedrock with error: {err:#}"); - } + self.block_publisher + .publish_block(&block) + .await + .context("Failed to publish block to Bedrock")?; + self.store.update(&block, placeholder_msg_id, &self.state)?; + let updated_deposits = self + .store + .mark_unfulfilled_deposit_events_submitted(&deposit_event_ids, block.header.block_id)?; + if updated_deposits > 0 { + info!( + "Marked {updated_deposits} pending deposit events as submitted in block {}", + block.header.block_id + ); + } + Ok(self.chain_height) } /// Builds a new block from transactions in the mempool. /// Does NOT publish or store the block — the caller is responsible for that. - pub fn build_block_from_mempool(&mut self) -> Result { + fn build_block_from_mempool(&mut self) -> Result { let now = Instant::now(); let new_block_height = self.next_block_id(); - let mut valid_transactions = vec![]; + let mut valid_transactions = Vec::new(); + let mut deposit_event_ids = Vec::new(); let max_block_size = usize::try_from(self.sequencer_config.max_block_size.as_u64()) .expect("`max_block_size` should fit into usize"); @@ -205,16 +322,16 @@ impl SequencerCore { // Pre-create the mandatory clock tx so its size is included in the block size check. let clock_tx = clock_invocation(new_block_timestamp); - let clock_nssa_tx = NSSATransaction::Public(clock_tx.clone()); + let clock_lee_tx = LeeTransaction::Public(clock_tx.clone()); - while let Some(tx) = self.mempool.pop() { + while let Some((origin, tx)) = self.mempool.pop() { let tx_hash = tx.hash(); // Check if block size exceeds limit (including the mandatory clock tx). let temp_valid_transactions = [ valid_transactions.as_slice(), std::slice::from_ref(&tx), - std::slice::from_ref(&clock_nssa_tx), + std::slice::from_ref(&clock_lee_tx), ] .concat(); let temp_hashable_data = HashableBlockData { @@ -235,25 +352,55 @@ impl SequencerCore { block size {block_size} bytes would exceed limit of {max_block_size} bytes", ); - self.mempool.push_front(tx); + self.mempool.push_front((origin, tx)); break; } - let validated_diff = match tx.validate_on_state( - &self.state, - new_block_height, - new_block_timestamp, - ) { - Ok(diff) => diff, - Err(err) => { - error!( - "Transaction with hash {tx_hash} failed execution check with error: {err:#?}, skipping it", - ); - continue; - } - }; + match origin { + TransactionOrigin::User => { + let validated_diff = match tx.validate_on_state( + &self.state, + new_block_height, + new_block_timestamp, + ) { + Ok(diff) => diff, + Err(err) => { + error!( + "Transaction with hash {tx_hash} failed execution check with error: {err:#?}, skipping it", + ); + continue; + } + }; - self.state.apply_state_diff(validated_diff); + self.state.apply_state_diff(validated_diff); + } + TransactionOrigin::Sequencer => { + let LeeTransaction::Public(public_tx) = &tx else { + panic!("Sequencer may only generate Public transactions, found {tx:#?}"); + }; + + if public_tx.message.program_id == Program::bridge().id() { + let instruction: bridge_core::Instruction = + risc0_zkvm::serde::from_slice(&public_tx.message.instruction_data) + .context("Failed to deserialize bridge instruction")?; + match instruction { + bridge_core::Instruction::Deposit { + l1_deposit_op_id, .. + } => { + deposit_event_ids.push(HashType(l1_deposit_op_id)); + } + } + } + + self.state + .transition_from_public_transaction( + public_tx, + new_block_height, + new_block_timestamp, + ) + .context("Failed to execute sequencer-generated transaction")?; + } + } valid_transactions.push(tx); info!("Validated transaction with hash {tx_hash}, including it in block"); @@ -266,7 +413,7 @@ impl SequencerCore { self.state .transition_from_public_transaction(&clock_tx, new_block_height, new_block_timestamp) .context("Clock transaction failed. Aborting block production.")?; - valid_transactions.push(clock_nssa_tx); + valid_transactions.push(clock_lee_tx); let hashable_data = HashableBlockData { block_id: new_block_height, @@ -289,10 +436,14 @@ impl SequencerCore { hashable_data.transactions.len(), now.elapsed().as_secs() ); - Ok(block) + + Ok(BlockWithMeta { + block, + deposit_event_ids, + }) } - pub const fn state(&self) -> &nssa::V03State { + pub const fn state(&self) -> &lee::V03State { &self.state } @@ -345,10 +496,64 @@ impl SequencerCore { } } +struct BlockWithMeta { + block: Block, + deposit_event_ids: Vec, +} + +/// Checks the database for any pending deposit events that have not yet been marked as submitted in +/// a block, and re-queues them in the mempool in a separate async task for inclusion in the next +/// block. +fn replay_unfulfilled_deposit_events( + store: &SequencerStore, + mempool_handle: MemPoolHandle<(TransactionOrigin, LeeTransaction)>, +) { + let replay_records: Vec = store + .get_unfulfilled_deposit_events() + .expect("Failed to load unfulfilled deposit events") + .into_iter() + .filter(|record| record.submitted_in_block_id.is_none()) + .collect(); + + if replay_records.is_empty() { + return; + } + + info!( + "Found {} unfulfilled deposit events in DB, re-queueing", + replay_records.len() + ); + tokio::spawn(async move { + for record in replay_records { + let tx = match build_bridge_deposit_tx_from_event(&record) { + Ok(tx) => tx, + Err(err) => { + warn!( + "Skipping replay of pending deposit event {} due to tx build failure: {err:#}", + hex::encode(record.deposit_op_id) + ); + continue; + } + }; + + if let Err(err) = mempool_handle + .push((TransactionOrigin::Sequencer, tx)) + .await + { + error!( + "Failed to re-queue unfulfilled deposit event {} from DB: {err:#}", + hex::encode(record.deposit_op_id) + ); + break; + } + } + }); +} + /// Builds the initial genesis state from `testnet_initial_state` plus configured genesis -/// transactions. Returns the final state and the list of [`NSSATransaction`]s that should be +/// transactions. Returns the final state and the list of [`LeeTransaction`]s that should be /// committed to the genesis block so external observers can replay them. -fn build_genesis_state(config: &SequencerConfig) -> (nssa::V03State, Vec) { +fn build_genesis_state(config: &SequencerConfig) -> (lee::V03State, Vec) { #[cfg(not(feature = "testnet"))] let mut state = testnet_initial_state::initial_state(); @@ -363,6 +568,9 @@ fn build_genesis_state(config: &SequencerConfig) -> (nssa::V03State, Vec build_supply_account_genesis_transaction(account_id, *balance), + GenesisAction::SupplyBridgeAccount { balance } => { + build_supply_bridge_account_genesis_transaction(*balance) + } }) .chain(std::iter::once(clock_invocation(0))) .inspect(|tx| { @@ -370,7 +578,7 @@ fn build_genesis_state(config: &SequencerConfig) -> (nssa::V03State, Vec PublicTransaction { + let faucet_program_id = Program::faucet().id(); + let bridge_account_id = lee::system_bridge_account_id(); + + let message = Message::try_new( + faucet_program_id, + vec![lee::system_faucet_account_id(), bridge_account_id], + vec![], + faucet_core::Instruction::GenesisTransferDirect { amount: balance }, + ) + .expect("Failed to serialize bridge genesis transfer instruction"); + let witness_set = lee::public_transaction::WitnessSet::from_raw_parts(vec![]); + + PublicTransaction::new(message, witness_set) +} + +fn pending_deposit_event_record( + deposit: &logos_blockchain_zone_sdk::state::DepositInfo, +) -> PendingDepositEventRecord { + PendingDepositEventRecord { + deposit_op_id: HashType(deposit.op_id), + source_tx_hash: HashType(deposit.tx_hash.0), + amount: deposit.amount, + metadata: deposit.metadata.clone().into(), + submitted_in_block_id: None, + } +} + +fn build_bridge_deposit_tx_from_event(event: &PendingDepositEventRecord) -> Result { + let metadata = DepositMetadata::decode(&event.metadata) + .context("Failed to decode finalized Bedrock deposit metadata")?; + + let bridge_program_id = Program::bridge().id(); + let vault_program_id = Program::vault().id(); + let recipient_vault_id = + vault_core::compute_vault_account_id(vault_program_id, metadata.recipient_id); + + let message = Message::try_new( + bridge_program_id, + vec![lee::system_bridge_account_id(), recipient_vault_id], + vec![], + bridge_core::Instruction::Deposit { + l1_deposit_op_id: event.deposit_op_id.0, + vault_program_id, + recipient_id: metadata.recipient_id, + amount: u128::from(event.amount), + }, + ) + .context("Failed to build bridge deposit message")?; + + let witness_set = lee::public_transaction::WitnessSet::from_raw_parts(vec![]); + Ok(LeeTransaction::Public(PublicTransaction::new( + message, + witness_set, + ))) +} + /// Load signing key from file or generate a new one if it doesn't exist. fn load_or_create_signing_key(path: &Path) -> Result { if path.exists() { @@ -433,20 +698,27 @@ mod tests { HashType, block::HashableBlockData, test_utils::sequencer_sign_key_for_testing, - transaction::{NSSATransaction, clock_invocation}, + transaction::{LeeTransaction, clock_invocation}, }; use logos_blockchain_core::mantle::ops::channel::ChannelId; use mempool::MemPoolHandle; + use storage::sequencer::sequencer_cells::PendingDepositEventRecord; use tempfile::tempdir; use testnet_initial_state::{initial_accounts, initial_pub_accounts_private_keys}; use crate::{ + TransactionOrigin, block_store::SequencerStore, build_genesis_state, config::{BedrockConfig, SequencerConfig}, mock::SequencerCoreWithMockClients, }; + #[derive(borsh::BorshSerialize)] + struct DepositMetadataForEncoding { + recipient_id: lee::AccountId, + } + fn setup_sequencer_config() -> SequencerConfig { let tempdir = tempfile::tempdir().unwrap(); let home = tempdir.path().to_path_buf(); @@ -468,33 +740,71 @@ mod tests { } } - fn create_signing_key_for_account1() -> nssa::PrivateKey { + fn create_signing_key_for_account1() -> lee::PrivateKey { initial_pub_accounts_private_keys()[0].pub_sign_key.clone() } - fn create_signing_key_for_account2() -> nssa::PrivateKey { + fn create_signing_key_for_account2() -> lee::PrivateKey { initial_pub_accounts_private_keys()[1].pub_sign_key.clone() } - async fn common_setup() -> (SequencerCoreWithMockClients, MemPoolHandle) { + async fn common_setup() -> ( + SequencerCoreWithMockClients, + MemPoolHandle<(TransactionOrigin, LeeTransaction)>, + ) { let config = setup_sequencer_config(); common_setup_with_config(config).await } async fn common_setup_with_config( config: SequencerConfig, - ) -> (SequencerCoreWithMockClients, MemPoolHandle) { + ) -> ( + SequencerCoreWithMockClients, + MemPoolHandle<(TransactionOrigin, LeeTransaction)>, + ) { let (mut sequencer, mempool_handle) = SequencerCoreWithMockClients::start_from_config(config).await; let tx = common::test_utils::produce_dummy_empty_transaction(); - mempool_handle.push(tx).await.unwrap(); + mempool_handle + .push((TransactionOrigin::User, tx)) + .await + .unwrap(); sequencer.produce_new_block().await.unwrap(); (sequencer, mempool_handle) } + fn tx_is_bridge_deposit( + tx: &LeeTransaction, + deposit_op_id: [u8; 32], + expected_amount: u64, + ) -> bool { + let LeeTransaction::Public(public_tx) = tx else { + return false; + }; + + if public_tx.message.program_id != lee::program::Program::bridge().id() { + return false; + } + + let instruction: bridge_core::Instruction = + match risc0_zkvm::serde::from_slice(&public_tx.message.instruction_data) { + Ok(instruction) => instruction, + Err(_err) => return false, + }; + + matches!( + instruction, + bridge_core::Instruction::Deposit { + l1_deposit_op_id, + amount, + .. + } if l1_deposit_op_id == deposit_op_id && amount == u128::from(expected_amount) + ) + } + #[tokio::test] async fn start_from_config() { let config = setup_sequencer_config(); @@ -521,7 +831,7 @@ mod tests { let mut config = config; config.home = temp_dir.path().to_path_buf(); - let signing_key = nssa::PrivateKey::try_new(config.signing_key).unwrap(); + let signing_key = lee::PrivateKey::try_new(config.signing_key).unwrap(); let (genesis_state, genesis_txs) = build_genesis_state(&config); let genesis_hashable_data = HashableBlockData { block_id: 1, @@ -565,6 +875,69 @@ mod tests { let _ = SequencerCoreWithMockClients::start_from_config(config).await; } + #[tokio::test] + async fn start_from_config_replays_unfulfilled_deposit_events_from_db() { + let config = setup_sequencer_config(); + let deposit_op_id = [13_u8; 32]; + let expected_amount = 1_u64; + let recipient_id = initial_accounts()[0].account_id; + + { + let (_sequencer, _mempool_handle) = + SequencerCoreWithMockClients::start_from_config(config.clone()).await; + } + + let pending_event = PendingDepositEventRecord { + deposit_op_id: HashType(deposit_op_id), + source_tx_hash: HashType([7_u8; 32]), + amount: expected_amount, + metadata: borsh::to_vec(&DepositMetadataForEncoding { recipient_id }).unwrap(), + submitted_in_block_id: None, + }; + + { + let signing_key = lee::PrivateKey::try_new(config.signing_key).unwrap(); + let store = SequencerStore::open_db(&config.home.join("rocksdb"), signing_key).unwrap(); + + let inserted = store + .dbio() + .add_pending_deposit_event(pending_event) + .unwrap(); + assert!(inserted); + } + + let (mut sequencer, _mempool_handle) = + SequencerCoreWithMockClients::start_from_config(config).await; + + let (origin, tx) = tokio::time::timeout(Duration::from_secs(5), async { + loop { + if let Some((origin, tx)) = sequencer.mempool.pop() { + return (origin, tx); + } + + tokio::time::sleep(Duration::from_millis(100)).await; + } + }) + .await + .expect("Timed out waiting for pending deposit event to be replayed into mempool"); + + match origin { + TransactionOrigin::Sequencer => {} + TransactionOrigin::User => { + panic!("Unexpected user transaction in empty mempool replay test") + } + } + + assert!(tx_is_bridge_deposit(&tx, deposit_op_id, expected_amount)); + + let pending_events = sequencer.store.get_unfulfilled_deposit_events().unwrap(); + let replayed_event = pending_events + .into_iter() + .find(|event| event.deposit_op_id == HashType(deposit_op_id)) + .expect("Pending deposit event should remain in DB until included in a block"); + assert!(replayed_event.submitted_in_block_id.is_none()); + } + #[test] fn transaction_pre_check_pass() { let tx = common::test_utils::produce_dummy_empty_transaction(); @@ -611,7 +984,7 @@ mod tests { assert!(matches!( result, - Err(nssa::error::NssaError::ProgramExecutionFailed(_)) + Err(lee::error::LeeError::ProgramExecutionFailed(_)) )); } @@ -638,7 +1011,7 @@ mod tests { .execute_check_on_state(&mut sequencer.state, 0, 0); let is_failed_at_balance_mismatch = matches!( result.err().unwrap(), - nssa::error::NssaError::ProgramExecutionFailed(_) + lee::error::LeeError::ProgramExecutionFailed(_) ); assert!(is_failed_at_balance_mismatch); @@ -678,10 +1051,13 @@ mod tests { let tx = common::test_utils::produce_dummy_empty_transaction(); // Fill the mempool - mempool_handle.push(tx.clone()).await.unwrap(); + mempool_handle + .push((TransactionOrigin::User, tx.clone())) + .await + .unwrap(); // Check that pushing another transaction will block - let mut push_fut = pin!(mempool_handle.push(tx.clone())); + let mut push_fut = pin!(mempool_handle.push((TransactionOrigin::User, tx.clone()))); let poll = futures::poll!(push_fut.as_mut()); assert!(poll.is_pending()); @@ -698,7 +1074,10 @@ mod tests { let genesis_height = sequencer.chain_height; let tx = common::test_utils::produce_dummy_empty_transaction(); - mempool_handle.push(tx).await.unwrap(); + mempool_handle + .push((TransactionOrigin::User, tx)) + .await + .unwrap(); let result = sequencer.build_block_from_mempool(); assert!(result.is_ok()); @@ -721,8 +1100,14 @@ mod tests { let tx_original = tx.clone(); let tx_replay = tx.clone(); // Pushing two copies of the same tx to the mempool - mempool_handle.push(tx_original).await.unwrap(); - mempool_handle.push(tx_replay).await.unwrap(); + mempool_handle + .push((TransactionOrigin::User, tx_original)) + .await + .unwrap(); + mempool_handle + .push((TransactionOrigin::User, tx_replay)) + .await + .unwrap(); // Create block sequencer.produce_new_block().await.unwrap(); @@ -737,7 +1122,7 @@ mod tests { block.body.transactions, vec![ tx.clone(), - NSSATransaction::Public(clock_invocation(block.header.timestamp)) + LeeTransaction::Public(clock_invocation(block.header.timestamp)) ] ); } @@ -756,7 +1141,10 @@ mod tests { ); // The transaction should be included the first time - mempool_handle.push(tx.clone()).await.unwrap(); + mempool_handle + .push((TransactionOrigin::User, tx.clone())) + .await + .unwrap(); sequencer.produce_new_block().await.unwrap(); let block = sequencer .store @@ -767,12 +1155,15 @@ mod tests { block.body.transactions, vec![ tx.clone(), - NSSATransaction::Public(clock_invocation(block.header.timestamp)) + LeeTransaction::Public(clock_invocation(block.header.timestamp)) ] ); // Add same transaction should fail - mempool_handle.push(tx.clone()).await.unwrap(); + mempool_handle + .push((TransactionOrigin::User, tx.clone())) + .await + .unwrap(); sequencer.produce_new_block().await.unwrap(); let block = sequencer .store @@ -782,7 +1173,7 @@ mod tests { // The replay is rejected, so only the clock tx is in the block. assert_eq!( block.body.transactions, - vec![NSSATransaction::Public(clock_invocation( + vec![LeeTransaction::Public(clock_invocation( block.header.timestamp ))] ); @@ -811,7 +1202,10 @@ mod tests { &signing_key, ); - mempool_handle.push(tx.clone()).await.unwrap(); + mempool_handle + .push((TransactionOrigin::User, tx.clone())) + .await + .unwrap(); sequencer.produce_new_block().await.unwrap(); let block = sequencer .store @@ -822,7 +1216,7 @@ mod tests { block.body.transactions, vec![ tx.clone(), - NSSATransaction::Public(clock_invocation(block.header.timestamp)) + LeeTransaction::Public(clock_invocation(block.header.timestamp)) ] ); } @@ -895,7 +1289,10 @@ mod tests { &signing_key, ); - mempool_handle.push(tx).await.unwrap(); + mempool_handle + .push((TransactionOrigin::User, tx)) + .await + .unwrap(); sequencer.produce_new_block().await.unwrap(); // Get the metadata of the last block produced @@ -916,7 +1313,10 @@ mod tests { &signing_key, ); - mempool_handle.push(tx.clone()).await.unwrap(); + mempool_handle + .push((TransactionOrigin::User, tx.clone())) + .await + .unwrap(); // Step 4: Produce new block sequencer.produce_new_block().await.unwrap(); @@ -936,7 +1336,7 @@ mod tests { new_block.body.transactions, vec![ tx, - NSSATransaction::Public(clock_invocation(new_block.header.timestamp)) + LeeTransaction::Public(clock_invocation(new_block.header.timestamp)) ], "New block should contain the submitted transaction and the clock invocation" ); @@ -949,23 +1349,29 @@ mod tests { // Canonical clock invocation and a crafted variant with a different timestamp — both must // be dropped because their diffs touch the clock accounts. let crafted_clock_tx = { - let message = nssa::public_transaction::Message::try_new( - nssa::program::Program::clock().id(), - nssa::CLOCK_PROGRAM_ACCOUNT_IDS.to_vec(), + let message = lee::public_transaction::Message::try_new( + lee::program::Program::clock().id(), + lee::CLOCK_PROGRAM_ACCOUNT_IDS.to_vec(), vec![], 42_u64, ) .unwrap(); - NSSATransaction::Public(nssa::PublicTransaction::new( + LeeTransaction::Public(lee::PublicTransaction::new( message, - nssa::public_transaction::WitnessSet::from_raw_parts(vec![]), + lee::public_transaction::WitnessSet::from_raw_parts(vec![]), )) }; mempool_handle - .push(NSSATransaction::Public(clock_invocation(0))) + .push(( + TransactionOrigin::User, + LeeTransaction::Public(clock_invocation(0)), + )) + .await + .unwrap(); + mempool_handle + .push((TransactionOrigin::User, crafted_clock_tx)) .await .unwrap(); - mempool_handle.push(crafted_clock_tx).await.unwrap(); sequencer.produce_new_block().await.unwrap(); let block = sequencer @@ -977,7 +1383,7 @@ mod tests { // Both transactions were dropped. Only the system-appended clock tx remains. assert_eq!( block.body.transactions, - vec![NSSATransaction::Public(clock_invocation( + vec![LeeTransaction::Public(clock_invocation( block.header.timestamp ))] ); @@ -988,38 +1394,43 @@ mod tests { let (mut sequencer, mempool_handle) = common_setup().await; // Deploy the clock_chain_caller test program. - let deploy_tx = - NSSATransaction::ProgramDeployment(nssa::ProgramDeploymentTransaction::new( - nssa::program_deployment_transaction::Message::new( - test_program_methods::CLOCK_CHAIN_CALLER_ELF.to_vec(), - ), - )); - mempool_handle.push(deploy_tx).await.unwrap(); + let deploy_tx = LeeTransaction::ProgramDeployment(lee::ProgramDeploymentTransaction::new( + lee::program_deployment_transaction::Message::new( + test_program_methods::CLOCK_CHAIN_CALLER_ELF.to_vec(), + ), + )); + mempool_handle + .push((TransactionOrigin::User, deploy_tx)) + .await + .unwrap(); sequencer.produce_new_block().await.unwrap(); // Build a user transaction that invokes clock_chain_caller, which in turn chain-calls the // clock program with the clock accounts. The sequencer should detect that the resulting // state diff modifies clock accounts and drop the transaction. let clock_chain_caller_id = - nssa::program::Program::new(test_program_methods::CLOCK_CHAIN_CALLER_ELF.to_vec()) + lee::program::Program::new(test_program_methods::CLOCK_CHAIN_CALLER_ELF.to_vec()) .unwrap() .id(); - let clock_program_id = nssa::program::Program::clock().id(); + let clock_program_id = lee::program::Program::clock().id(); let timestamp: u64 = 0; - let message = nssa::public_transaction::Message::try_new( + let message = lee::public_transaction::Message::try_new( clock_chain_caller_id, - nssa::CLOCK_PROGRAM_ACCOUNT_IDS.to_vec(), + lee::CLOCK_PROGRAM_ACCOUNT_IDS.to_vec(), vec![], // no signers (clock_program_id, timestamp), ) .unwrap(); - let user_tx = NSSATransaction::Public(nssa::PublicTransaction::new( + let user_tx = LeeTransaction::Public(lee::PublicTransaction::new( message, - nssa::public_transaction::WitnessSet::from_raw_parts(vec![]), + lee::public_transaction::WitnessSet::from_raw_parts(vec![]), )); - mempool_handle.push(user_tx).await.unwrap(); + mempool_handle + .push((TransactionOrigin::User, user_tx)) + .await + .unwrap(); sequencer.produce_new_block().await.unwrap(); let block = sequencer @@ -1031,7 +1442,7 @@ mod tests { // The user tx must have been dropped; only the mandatory clock invocation remains. assert_eq!( block.body.transactions, - vec![NSSATransaction::Public(clock_invocation( + vec![LeeTransaction::Public(clock_invocation( block.header.timestamp ))] ); @@ -1042,7 +1453,7 @@ mod tests { let (mut sequencer, mempool_handle) = common_setup().await; // Corrupt the clock 01 account data so the clock program panics on deserialization. - let clock_account_id = nssa::CLOCK_01_PROGRAM_ACCOUNT_ID; + let clock_account_id = lee::CLOCK_01_PROGRAM_ACCOUNT_ID; let mut corrupted = sequencer.state.get_account_by_id(clock_account_id); corrupted.data = vec![0xff; 3].try_into().unwrap(); sequencer @@ -1051,7 +1462,10 @@ mod tests { // Push a dummy transaction so the mempool is non-empty. let tx = common::test_utils::produce_dummy_empty_transaction(); - mempool_handle.push(tx).await.unwrap(); + mempool_handle + .push((TransactionOrigin::User, tx)) + .await + .unwrap(); // Block production must fail because the appended clock tx cannot execute. let result = sequencer.produce_new_block().await; diff --git a/sequencer/core/src/mock.rs b/lez/sequencer/core/src/mock.rs similarity index 90% rename from sequencer/core/src/mock.rs rename to lez/sequencer/core/src/mock.rs index ebe6ea5d..e041269a 100644 --- a/sequencer/core/src/mock.rs +++ b/lez/sequencer/core/src/mock.rs @@ -6,7 +6,8 @@ use logos_blockchain_key_management_system_service::keys::Ed25519Key; use crate::{ block_publisher::{ - BlockPublisherTrait, CheckpointSink, FinalizedBlockSink, SequencerCheckpoint, + BlockPublisherTrait, CheckpointSink, FinalizedBlockSink, OnDepositEventSink, + SequencerCheckpoint, }, config::BedrockConfig, }; @@ -24,6 +25,7 @@ impl BlockPublisherTrait for MockBlockPublisher { _initial_checkpoint: Option, _on_checkpoint: CheckpointSink, _on_finalized_block: FinalizedBlockSink, + _on_deposit_event: OnDepositEventSink, ) -> Result { Ok(Self) } diff --git a/sequencer/service/Cargo.toml b/lez/sequencer/service/Cargo.toml similarity index 97% rename from sequencer/service/Cargo.toml rename to lez/sequencer/service/Cargo.toml index beed6be2..4390f0d8 100644 --- a/sequencer/service/Cargo.toml +++ b/lez/sequencer/service/Cargo.toml @@ -9,7 +9,7 @@ workspace = true [dependencies] common.workspace = true -nssa.workspace = true +lee.workspace = true mempool.workspace = true sequencer_core = { workspace = true, features = ["testnet"] } sequencer_service_protocol.workspace = true diff --git a/sequencer/service/Dockerfile b/lez/sequencer/service/Dockerfile similarity index 100% rename from sequencer/service/Dockerfile rename to lez/sequencer/service/Dockerfile diff --git a/sequencer/service/configs/debug/sequencer_config.json b/lez/sequencer/service/configs/debug/sequencer_config.json similarity index 93% rename from sequencer/service/configs/debug/sequencer_config.json rename to lez/sequencer/service/configs/debug/sequencer_config.json index bfe963ae..359c84f4 100644 --- a/sequencer/service/configs/debug/sequencer_config.json +++ b/lez/sequencer/service/configs/debug/sequencer_config.json @@ -15,6 +15,11 @@ }, "indexer_rpc_url": "ws://localhost:8779", "genesis": [ + { + "supply_bridge_account": { + "balance": 1000000 + } + }, { "supply_account": { "account_id": "CbgR6tj5kWx5oziiFptM7jMvrQeYY3Mzaao6ciuhSr2r", diff --git a/sequencer/service/configs/docker/sequencer_config.json b/lez/sequencer/service/configs/docker/sequencer_config.json similarity index 93% rename from sequencer/service/configs/docker/sequencer_config.json rename to lez/sequencer/service/configs/docker/sequencer_config.json index c9d0e6a6..69238fe7 100644 --- a/sequencer/service/configs/docker/sequencer_config.json +++ b/lez/sequencer/service/configs/docker/sequencer_config.json @@ -15,6 +15,11 @@ }, "indexer_rpc_url": "ws://localhost:8779", "genesis": [ + { + "supply_bridge_account": { + "balance": 1000000 + } + }, { "supply_account": { "account_id": "CbgR6tj5kWx5oziiFptM7jMvrQeYY3Mzaao6ciuhSr2r", diff --git a/sequencer/service/docker-compose.yml b/lez/sequencer/service/docker-compose.yml similarity index 81% rename from sequencer/service/docker-compose.yml rename to lez/sequencer/service/docker-compose.yml index cede8143..d9c7c2be 100644 --- a/sequencer/service/docker-compose.yml +++ b/lez/sequencer/service/docker-compose.yml @@ -1,9 +1,9 @@ services: sequencer_service: - image: lssa/sequencer_service + image: lez/sequencer_service build: context: ../.. - dockerfile: sequencer/service/Dockerfile + dockerfile: lez/sequencer/service/Dockerfile container_name: sequencer_service ports: - "3040:3040" diff --git a/sequencer/service/protocol/Cargo.toml b/lez/sequencer/service/protocol/Cargo.toml similarity index 78% rename from sequencer/service/protocol/Cargo.toml rename to lez/sequencer/service/protocol/Cargo.toml index be913104..06d51c88 100644 --- a/sequencer/service/protocol/Cargo.toml +++ b/lez/sequencer/service/protocol/Cargo.toml @@ -9,5 +9,5 @@ workspace = true [dependencies] common.workspace = true -nssa.workspace = true -nssa_core.workspace = true +lee.workspace = true +lee_core.workspace = true diff --git a/lez/sequencer/service/protocol/src/lib.rs b/lez/sequencer/service/protocol/src/lib.rs new file mode 100644 index 00000000..a8863997 --- /dev/null +++ b/lez/sequencer/service/protocol/src/lib.rs @@ -0,0 +1,5 @@ +//! Reexports of types used by sequencer rpc specification. + +pub use common::{HashType, block::Block, transaction::LeeTransaction}; +pub use lee::{Account, AccountId, ProgramId}; +pub use lee_core::{BlockId, Commitment, MembershipProof, account::Nonce}; diff --git a/sequencer/service/rpc/Cargo.toml b/lez/sequencer/service/rpc/Cargo.toml similarity index 100% rename from sequencer/service/rpc/Cargo.toml rename to lez/sequencer/service/rpc/Cargo.toml diff --git a/sequencer/service/rpc/src/lib.rs b/lez/sequencer/service/rpc/src/lib.rs similarity index 89% rename from sequencer/service/rpc/src/lib.rs rename to lez/sequencer/service/rpc/src/lib.rs index 6c03cdb6..2cc85d7d 100644 --- a/sequencer/service/rpc/src/lib.rs +++ b/lez/sequencer/service/rpc/src/lib.rs @@ -6,7 +6,7 @@ use jsonrpsee::types::ErrorObjectOwned; #[cfg(feature = "client")] pub use jsonrpsee::{core::ClientError, http_client::HttpClientBuilder as SequencerClientBuilder}; use sequencer_service_protocol::{ - Account, AccountId, Block, BlockId, Commitment, HashType, MembershipProof, NSSATransaction, + Account, AccountId, Block, BlockId, Commitment, HashType, LeeTransaction, MembershipProof, Nonce, ProgramId, }; @@ -20,13 +20,13 @@ compile_error!("At least one of `server` or `client` features must be enabled.") /// # Example /// /// ```no_run -/// use common::transaction::NSSATransaction; +/// use common::transaction::LeeTransaction; /// use sequencer_service_rpc::{RpcClient as _, SequencerClientBuilder}; /// /// let url = "http://localhost:3040".parse()?; /// let client = SequencerClientBuilder::default().build(url)?; /// -/// let tx: NSSATransaction = unimplemented!("Construct your transaction here"); +/// let tx: LeeTransaction = unimplemented!("Construct your transaction here"); /// let tx_hash = client.send_transaction(tx).await?; /// ``` #[cfg(feature = "client")] @@ -37,7 +37,7 @@ pub type SequencerClient = jsonrpsee::http_client::HttpClient; #[cfg_attr(all(feature = "server", feature = "client"), rpc(server, client))] pub trait Rpc { #[method(name = "sendTransaction")] - async fn send_transaction(&self, tx: NSSATransaction) -> Result; + async fn send_transaction(&self, tx: LeeTransaction) -> Result; // TODO: expand healthcheck response into some kind of report #[method(name = "checkHealth")] @@ -68,7 +68,7 @@ pub trait Rpc { async fn get_transaction( &self, tx_hash: HashType, - ) -> Result, ErrorObjectOwned>; + ) -> Result, ErrorObjectOwned>; #[method(name = "getAccountsNonces")] async fn get_accounts_nonces( diff --git a/sequencer/service/src/lib.rs b/lez/sequencer/service/src/lib.rs similarity index 93% rename from sequencer/service/src/lib.rs rename to lez/sequencer/service/src/lib.rs index 319b75ad..687ee424 100644 --- a/sequencer/service/src/lib.rs +++ b/lez/sequencer/service/src/lib.rs @@ -2,7 +2,7 @@ use std::{net::SocketAddr, sync::Arc, time::Duration}; use anyhow::{Context as _, Result, anyhow}; use bytesize::ByteSize; -use common::transaction::NSSATransaction; +use common::transaction::LeeTransaction; use futures::never::Never; use jsonrpsee::server::ServerHandle; use log::{error, info}; @@ -11,6 +11,7 @@ use mempool::MemPoolHandle; use sequencer_core::SequencerCore; #[cfg(feature = "standalone")] use sequencer_core::SequencerCoreWithMockClients as SequencerCore; +use sequencer_core::TransactionOrigin; pub use sequencer_core::config::*; use sequencer_service_rpc::RpcServer as _; use tokio::{sync::Mutex, task::JoinHandle}; @@ -55,15 +56,14 @@ impl SequencerHandle { } = &mut self; let server_handle = server_handle.take().expect("Server handle is set"); - tokio::select! { () = server_handle.stopped() => { Err(anyhow!("RPC Server stopped")) } res = main_loop_handle => { res - .context("Main loop task panicked")? - .context("Main loop exited unexpectedly") + .context("Main loop task panicked")? + .context("Main loop exited unexpectedly") } } } @@ -120,10 +120,11 @@ pub async fn run(config: SequencerConfig, port: u16) -> Result info!("Sequencer core set up"); let seq_core_wrapped = Arc::new(Mutex::new(sequencer_core)); + let mempool_handle_for_server = mempool_handle.clone(); let (server_handle, addr) = run_server( Arc::clone(&seq_core_wrapped), - mempool_handle, + mempool_handle_for_server, port, max_block_size.as_u64(), ) @@ -133,12 +134,14 @@ pub async fn run(config: SequencerConfig, port: u16) -> Result info!("Starting main sequencer loop"); let main_loop_handle = tokio::spawn(main_loop(seq_core_wrapped, block_timeout)); + let _ = mempool_handle; + Ok(SequencerHandle::new(addr, server_handle, main_loop_handle)) } async fn run_server( sequencer: Arc>, - mempool_handle: MemPoolHandle, + mempool_handle: MemPoolHandle<(TransactionOrigin, LeeTransaction)>, port: u16, max_block_size: u64, ) -> Result<(ServerHandle, SocketAddr)> { diff --git a/sequencer/service/src/main.rs b/lez/sequencer/service/src/main.rs similarity index 100% rename from sequencer/service/src/main.rs rename to lez/sequencer/service/src/main.rs diff --git a/sequencer/service/src/service.rs b/lez/sequencer/service/src/service.rs similarity index 90% rename from sequencer/service/src/service.rs rename to lez/sequencer/service/src/service.rs index 0bb8e1dd..1a781024 100644 --- a/sequencer/service/src/service.rs +++ b/lez/sequencer/service/src/service.rs @@ -1,14 +1,16 @@ use std::{collections::BTreeMap, sync::Arc}; -use common::transaction::NSSATransaction; +use common::transaction::LeeTransaction; use jsonrpsee::{ core::async_trait, types::{ErrorCode, ErrorObjectOwned}, }; +use lee::{self, program::Program}; use log::warn; use mempool::MemPoolHandle; -use nssa::{self, program::Program}; -use sequencer_core::{DbError, SequencerCore, block_publisher::BlockPublisherTrait}; +use sequencer_core::{ + DbError, SequencerCore, TransactionOrigin, block_publisher::BlockPublisherTrait, +}; use sequencer_service_protocol::{ Account, AccountId, Block, BlockId, Commitment, HashType, MembershipProof, Nonce, ProgramId, }; @@ -18,14 +20,14 @@ const NOT_FOUND_ERROR_CODE: i32 = -31999; pub struct SequencerService { sequencer: Arc>>, - mempool_handle: MemPoolHandle, + mempool_handle: MemPoolHandle<(TransactionOrigin, LeeTransaction)>, max_block_size: u64, } impl SequencerService { pub const fn new( sequencer: Arc>>, - mempool_handle: MemPoolHandle, + mempool_handle: MemPoolHandle<(TransactionOrigin, LeeTransaction)>, max_block_size: u64, ) -> Self { Self { @@ -40,7 +42,7 @@ impl SequencerService { impl sequencer_service_rpc::RpcServer for SequencerService { - async fn send_transaction(&self, tx: NSSATransaction) -> Result { + async fn send_transaction(&self, tx: LeeTransaction) -> Result { // Reserve ~200 bytes for block header overhead const BLOCK_HEADER_OVERHEAD: u64 = 200; @@ -72,7 +74,7 @@ impl sequencer_service_rpc::RpcServer })?; self.mempool_handle - .push(authenticated_tx) + .push((TransactionOrigin::User, authenticated_tx)) .await .expect("Mempool is closed, this is a bug"); @@ -128,7 +130,7 @@ impl sequencer_service_rpc::RpcServer async fn get_transaction( &self, tx_hash: HashType, - ) -> Result, ErrorObjectOwned> { + ) -> Result, ErrorObjectOwned> { let sequencer = self.sequencer.lock().await; Ok(sequencer.block_store().get_transaction_by_hash(tx_hash)) } @@ -169,7 +171,7 @@ impl sequencer_service_rpc::RpcServer program_ids.insert("amm".to_owned(), Program::amm().id()); program_ids.insert( "privacy_preserving_circuit".to_owned(), - nssa::PRIVACY_PRESERVING_CIRCUIT_ID, + lee::PRIVACY_PRESERVING_CIRCUIT_ID, ); Ok(program_ids) } diff --git a/lez/src/lib.rs b/lez/src/lib.rs new file mode 100644 index 00000000..81d0de04 --- /dev/null +++ b/lez/src/lib.rs @@ -0,0 +1,2 @@ +pub use indexer_core::IndexerCore; +pub use sequencer_core::SequencerCore; diff --git a/storage/Cargo.toml b/lez/storage/Cargo.toml similarity index 92% rename from storage/Cargo.toml rename to lez/storage/Cargo.toml index f18625cb..4588aab3 100644 --- a/storage/Cargo.toml +++ b/lez/storage/Cargo.toml @@ -9,7 +9,7 @@ workspace = true [dependencies] common.workspace = true -nssa.workspace = true +lee.workspace = true thiserror.workspace = true borsh.workspace = true diff --git a/storage/src/cells/mod.rs b/lez/storage/src/cells/mod.rs similarity index 100% rename from storage/src/cells/mod.rs rename to lez/storage/src/cells/mod.rs diff --git a/storage/src/cells/shared_cells.rs b/lez/storage/src/cells/shared_cells.rs similarity index 100% rename from storage/src/cells/shared_cells.rs rename to lez/storage/src/cells/shared_cells.rs diff --git a/storage/src/error.rs b/lez/storage/src/error.rs similarity index 100% rename from storage/src/error.rs rename to lez/storage/src/error.rs diff --git a/storage/src/indexer/indexer_cells.rs b/lez/storage/src/indexer/indexer_cells.rs similarity index 99% rename from storage/src/indexer/indexer_cells.rs rename to lez/storage/src/indexer/indexer_cells.rs index 615902bd..b19a5510 100644 --- a/storage/src/indexer/indexer_cells.rs +++ b/lez/storage/src/indexer/indexer_cells.rs @@ -1,5 +1,5 @@ use borsh::{BorshDeserialize, BorshSerialize}; -use nssa::V03State; +use lee::V03State; use crate::{ CF_META_NAME, DbResult, diff --git a/storage/src/indexer/mod.rs b/lez/storage/src/indexer/mod.rs similarity index 96% rename from storage/src/indexer/mod.rs rename to lez/storage/src/indexer/mod.rs index 97be70e5..51df8042 100644 --- a/storage/src/indexer/mod.rs +++ b/lez/storage/src/indexer/mod.rs @@ -2,9 +2,9 @@ use std::{path::Path, sync::Arc}; use common::{ block::Block, - transaction::{NSSATransaction, clock_invocation}, + transaction::{LeeTransaction, clock_invocation}, }; -use nssa::{GENESIS_BLOCK_ID, V03State}; +use lee::{GENESIS_BLOCK_ID, V03State}; use rocksdb::{ BoundColumnFamily, ColumnFamilyDescriptor, DBWithThreadMode, MultiThreaded, Options, }; @@ -162,7 +162,7 @@ impl RocksDBIO { for mut block in self.get_block_batch_seq( start.checked_add(1).expect("Will be lesser that u64::MAX")..=block_id, )? { - let expected_clock = NSSATransaction::Public(clock_invocation(block.header.timestamp)); + let expected_clock = LeeTransaction::Public(clock_invocation(block.header.timestamp)); let clock_tx = block.body.transactions.pop().ok_or_else(|| { DbError::db_interaction_error( @@ -181,9 +181,9 @@ impl RocksDBIO { let is_genesis = block.header.block_id == GENESIS_BLOCK_ID; if is_genesis { let genesis_tx = match transaction { - NSSATransaction::Public(public_tx) => public_tx, - NSSATransaction::PrivacyPreserving(_) - | NSSATransaction::ProgramDeployment(_) => { + LeeTransaction::Public(public_tx) => public_tx, + LeeTransaction::PrivacyPreserving(_) + | LeeTransaction::ProgramDeployment(_) => { return Err(DbError::db_interaction_error( "Genesis block should contain only public transactions".to_owned(), )); @@ -221,7 +221,7 @@ impl RocksDBIO { } } - let NSSATransaction::Public(clock_public_tx) = clock_tx else { + let LeeTransaction::Public(clock_public_tx) = clock_tx else { return Err(DbError::db_interaction_error( "Clock invocation must be a public transaction".to_owned(), )); @@ -260,7 +260,7 @@ fn closest_breakpoint_id(block_id: u64) -> u64 { #[cfg(test)] mod tests { use common::test_utils::produce_dummy_block; - use nssa::{AccountId, PublicKey}; + use lee::{AccountId, PublicKey}; use tempfile::tempdir; use super::*; @@ -269,12 +269,12 @@ mod tests { produce_dummy_block(1, None, vec![]) } - fn acc1_sign_key() -> nssa::PrivateKey { - nssa::PrivateKey::try_new([1; 32]).unwrap() + fn acc1_sign_key() -> lee::PrivateKey { + lee::PrivateKey::try_new([1; 32]).unwrap() } - fn acc2_sign_key() -> nssa::PrivateKey { - nssa::PrivateKey::try_new([2; 32]).unwrap() + fn acc2_sign_key() -> lee::PrivateKey { + lee::PrivateKey::try_new([2; 32]).unwrap() } fn acc1() -> AccountId { @@ -292,7 +292,7 @@ mod tests { let dbio = RocksDBIO::open_or_create( temdir_path, - &nssa::V03State::new_with_genesis_accounts( + &lee::V03State::new_with_genesis_accounts( &[(acc1(), 10000), (acc2(), 20000)], vec![], 0, @@ -332,7 +332,7 @@ mod tests { let dbio = RocksDBIO::open_or_create( temdir_path, - &nssa::V03State::new_with_genesis_accounts( + &lee::V03State::new_with_genesis_accounts( &[(acc1(), 10000), (acc2(), 20000)], vec![], 0, @@ -391,7 +391,7 @@ mod tests { let dbio = RocksDBIO::open_or_create( temdir_path, - &nssa::V03State::new_with_genesis_accounts( + &lee::V03State::new_with_genesis_accounts( &[(acc1(), 10000), (acc2(), 20000)], vec![], 0, @@ -463,7 +463,7 @@ mod tests { let dbio = RocksDBIO::open_or_create( temdir_path, - &nssa::V03State::new_with_genesis_accounts( + &lee::V03State::new_with_genesis_accounts( &[(acc1(), 10000), (acc2(), 20000)], vec![], 0, @@ -545,7 +545,7 @@ mod tests { let dbio = RocksDBIO::open_or_create( temdir_path, - &nssa::V03State::new_with_genesis_accounts( + &lee::V03State::new_with_genesis_accounts( &[(acc1(), 10000), (acc2(), 20000)], vec![], 0, @@ -640,7 +640,7 @@ mod tests { let dbio = RocksDBIO::open_or_create( temdir_path, - &nssa::V03State::new_with_genesis_accounts( + &lee::V03State::new_with_genesis_accounts( &[(acc1(), 10000), (acc2(), 20000)], vec![], 0, diff --git a/storage/src/indexer/read_multiple.rs b/lez/storage/src/indexer/read_multiple.rs similarity index 98% rename from storage/src/indexer/read_multiple.rs rename to lez/storage/src/indexer/read_multiple.rs index d91e9627..15fc1dd5 100644 --- a/storage/src/indexer/read_multiple.rs +++ b/lez/storage/src/indexer/read_multiple.rs @@ -1,4 +1,4 @@ -use common::transaction::NSSATransaction; +use common::transaction::LeeTransaction; use super::{Block, DbError, DbResult, RocksDBIO}; @@ -181,7 +181,7 @@ impl RocksDBIO { acc_id: [u8; 32], offset: u64, limit: u64, - ) -> DbResult> { + ) -> DbResult> { let mut tx_batch = vec![]; let tx_hashes = self.get_acc_transaction_hashes(acc_id, offset, limit)?; diff --git a/storage/src/indexer/read_once.rs b/lez/storage/src/indexer/read_once.rs similarity index 100% rename from storage/src/indexer/read_once.rs rename to lez/storage/src/indexer/read_once.rs diff --git a/storage/src/indexer/write_atomic.rs b/lez/storage/src/indexer/write_atomic.rs similarity index 99% rename from storage/src/indexer/write_atomic.rs rename to lez/storage/src/indexer/write_atomic.rs index 7e05791f..a88e46ef 100644 --- a/storage/src/indexer/write_atomic.rs +++ b/lez/storage/src/indexer/write_atomic.rs @@ -225,7 +225,7 @@ impl RocksDBIO { let acc_ids = tx .affected_public_account_ids() .into_iter() - .map(nssa::AccountId::into_value) + .map(lee::AccountId::into_value) .collect::>(); for acc_id in acc_ids { diff --git a/storage/src/indexer/write_non_atomic.rs b/lez/storage/src/indexer/write_non_atomic.rs similarity index 100% rename from storage/src/indexer/write_non_atomic.rs rename to lez/storage/src/indexer/write_non_atomic.rs diff --git a/storage/src/lib.rs b/lez/storage/src/lib.rs similarity index 100% rename from storage/src/lib.rs rename to lez/storage/src/lib.rs diff --git a/storage/src/sequencer/mod.rs b/lez/storage/src/sequencer/mod.rs similarity index 78% rename from storage/src/sequencer/mod.rs rename to lez/storage/src/sequencer/mod.rs index be5e5cfe..851dc4ff 100644 --- a/storage/src/sequencer/mod.rs +++ b/lez/storage/src/sequencer/mod.rs @@ -1,7 +1,10 @@ use std::{path::Path, sync::Arc}; -use common::block::{BedrockStatus, Block, BlockMeta, MantleMsgId}; -use nssa::V03State; +use common::{ + HashType, + block::{BedrockStatus, Block, BlockMeta, MantleMsgId}, +}; +use lee::V03State; use rocksdb::{ BoundColumnFamily, ColumnFamilyDescriptor, DBWithThreadMode, MultiThreaded, Options, WriteBatch, }; @@ -11,8 +14,9 @@ use crate::{ cells::shared_cells::{BlockCell, FirstBlockCell, FirstBlockSetCell, LastBlockCell}, error::DbError, sequencer::sequencer_cells::{ - LastFinalizedBlockIdCell, LatestBlockMetaCellOwned, LatestBlockMetaCellRef, - NSSAStateCellOwned, NSSAStateCellRef, ZoneSdkCheckpointCellOwned, ZoneSdkCheckpointCellRef, + LEEStateCellOwned, LEEStateCellRef, LastFinalizedBlockIdCell, LatestBlockMetaCellOwned, + LatestBlockMetaCellRef, PendingDepositEventRecord, PendingDepositEventsCellOwned, + PendingDepositEventsCellRef, ZoneSdkCheckpointCellOwned, ZoneSdkCheckpointCellRef, }, }; @@ -24,12 +28,15 @@ pub const DB_META_LAST_FINALIZED_BLOCK_ID: &str = "last_finalized_block_id"; pub const DB_META_LATEST_BLOCK_META_KEY: &str = "latest_block_meta"; /// Key base for storing the zone-sdk sequencer checkpoint (opaque bytes). pub const DB_META_ZONE_SDK_CHECKPOINT_KEY: &str = "zone_sdk_checkpoint"; +/// Key base for storing queued deposit events that were not yet +/// fulfilled on L2. +pub const DB_META_PENDING_DEPOSIT_EVENTS_KEY: &str = "pending_deposit_events"; -/// Key base for storing the NSSA state. -pub const DB_NSSA_STATE_KEY: &str = "nssa_state"; +/// Key base for storing the LEE state. +pub const DB_LEE_STATE_KEY: &str = "lee_state"; /// Name of state column family. -pub const CF_NSSA_STATE_NAME: &str = "cf_nssa_state"; +pub const CF_LEE_STATE_NAME: &str = "cf_lee_state"; pub struct RocksDBIO { pub db: DBWithThreadMode, @@ -71,7 +78,7 @@ impl RocksDBIO { hash: genesis_block.header.hash, msg_id: genesis_msg_id, })?; - dbio.put_nssa_state_in_db(genesis_state)?; + dbio.put_lee_state_in_db(genesis_state)?; } Ok(dbio) @@ -84,7 +91,7 @@ impl RocksDBIO { // ToDo: Add more column families for different data let cfb = ColumnFamilyDescriptor::new(CF_BLOCK_NAME, cf_opts.clone()); let cfmeta = ColumnFamilyDescriptor::new(CF_META_NAME, cf_opts.clone()); - let cfstate = ColumnFamilyDescriptor::new(CF_NSSA_STATE_NAME, cf_opts.clone()); + let cfstate = ColumnFamilyDescriptor::new(CF_LEE_STATE_NAME, cf_opts.clone()); let db = DBWithThreadMode::::open_cf_descriptors( db_opts, @@ -106,7 +113,7 @@ impl RocksDBIO { // ToDo: Add more column families for different data let _cfb = ColumnFamilyDescriptor::new(CF_BLOCK_NAME, cf_opts.clone()); let _cfmeta = ColumnFamilyDescriptor::new(CF_META_NAME, cf_opts.clone()); - let _cfstate = ColumnFamilyDescriptor::new(CF_NSSA_STATE_NAME, cf_opts.clone()); + let _cfstate = ColumnFamilyDescriptor::new(CF_LEE_STATE_NAME, cf_opts.clone()); let mut db_opts = Options::default(); db_opts.create_missing_column_families(true); @@ -129,9 +136,9 @@ impl RocksDBIO { .expect("Block column should exist") } - pub fn nssa_state_column(&self) -> Arc> { + pub fn lee_state_column(&self) -> Arc> { self.db - .cf_handle(CF_NSSA_STATE_NAME) + .cf_handle(CF_LEE_STATE_NAME) .expect("State should exist") } @@ -149,16 +156,16 @@ impl RocksDBIO { Ok(self.get_opt::(())?.is_some()) } - pub fn put_nssa_state_in_db(&self, state: &V03State) -> DbResult<()> { - self.put(&NSSAStateCellRef(state), ()) + pub fn put_lee_state_in_db(&self, state: &V03State) -> DbResult<()> { + self.put(&LEEStateCellRef(state), ()) } - pub fn put_nssa_state_in_db_batch( + pub fn put_lee_state_in_db_batch( &self, state: &V03State, batch: &mut WriteBatch, ) -> DbResult<()> { - self.put_batch(&NSSAStateCellRef(state), (), batch) + self.put_batch(&LEEStateCellRef(state), (), batch) } pub fn put_meta_first_block_in_db(&self, block: &Block, msg_id: MantleMsgId) -> DbResult<()> { @@ -239,6 +246,72 @@ impl RocksDBIO { self.put(&ZoneSdkCheckpointCellRef(bytes), ()) } + pub fn get_pending_deposit_events(&self) -> DbResult> { + Ok(self + .get_opt::(())? + .map_or_else(Vec::new, |cell| cell.0)) + } + + fn put_pending_deposit_events(&self, records: &[PendingDepositEventRecord]) -> DbResult<()> { + self.put(&PendingDepositEventsCellRef(records), ()) + } + + pub fn add_pending_deposit_event(&self, event: PendingDepositEventRecord) -> DbResult { + let mut records = self.get_pending_deposit_events()?; + if records + .iter() + .any(|record| record.deposit_op_id == event.deposit_op_id) + { + return Ok(false); + } + records.push(event); + self.put_pending_deposit_events(&records)?; + Ok(true) + } + + pub fn mark_pending_deposit_events_submitted( + &self, + deposit_op_ids: &[HashType], + submitted_block_id: u64, + ) -> DbResult { + let mut records = self.get_pending_deposit_events()?; + let mut updated: usize = 0; + + for record in records + .iter_mut() + .filter(|record| deposit_op_ids.contains(&record.deposit_op_id)) + { + record.submitted_in_block_id = Some(submitted_block_id); + updated = updated.saturating_add(1); + } + + if updated > 0 { + self.put_pending_deposit_events(&records)?; + } + + Ok(updated) + } + + pub fn remove_fulfilled_pending_deposit_events_up_to_block( + &self, + finalized_block_id: u64, + ) -> DbResult { + let mut records = self.get_pending_deposit_events()?; + let before = records.len(); + records.retain(|record| { + record + .submitted_in_block_id + .is_none_or(|submitted_id| submitted_id > finalized_block_id) + }); + + let removed = before.saturating_sub(records.len()); + if removed > 0 { + self.put_pending_deposit_events(&records)?; + } + + Ok(removed) + } + pub fn put_block( &self, block: &Block, @@ -281,8 +354,8 @@ impl RocksDBIO { .map(|opt| opt.map(|val| val.0)) } - pub fn get_nssa_state(&self) -> DbResult { - self.get::(()).map(|val| val.0) + pub fn get_lee_state(&self) -> DbResult { + self.get::(()).map(|val| val.0) } pub fn delete_block(&self, block_id: u64) -> DbResult<()> { @@ -388,7 +461,7 @@ impl RocksDBIO { let block_id = block.header.block_id; let mut batch = WriteBatch::default(); self.put_block(block, msg_id, false, &mut batch)?; - self.put_nssa_state_in_db_batch(state, &mut batch)?; + self.put_lee_state_in_db_batch(state, &mut batch)?; self.db.write(batch).map_err(|rerr| { DbError::rocksdb_cast_message( rerr, diff --git a/storage/src/sequencer/sequencer_cells.rs b/lez/storage/src/sequencer/sequencer_cells.rs similarity index 56% rename from storage/src/sequencer/sequencer_cells.rs rename to lez/storage/src/sequencer/sequencer_cells.rs index 2bf65367..39b6a406 100644 --- a/storage/src/sequencer/sequencer_cells.rs +++ b/lez/storage/src/sequencer/sequencer_cells.rs @@ -1,40 +1,41 @@ use borsh::{BorshDeserialize, BorshSerialize}; -use common::block::BlockMeta; -use nssa::V03State; +use common::{HashType, block::BlockMeta}; +use lee::V03State; use crate::{ CF_META_NAME, DbResult, cells::{SimpleReadableCell, SimpleStorableCell, SimpleWritableCell}, error::DbError, sequencer::{ - CF_NSSA_STATE_NAME, DB_META_LAST_FINALIZED_BLOCK_ID, DB_META_LATEST_BLOCK_META_KEY, - DB_META_ZONE_SDK_CHECKPOINT_KEY, DB_NSSA_STATE_KEY, + CF_LEE_STATE_NAME, DB_LEE_STATE_KEY, DB_META_LAST_FINALIZED_BLOCK_ID, + DB_META_LATEST_BLOCK_META_KEY, DB_META_PENDING_DEPOSIT_EVENTS_KEY, + DB_META_ZONE_SDK_CHECKPOINT_KEY, }, }; #[derive(BorshDeserialize)] -pub struct NSSAStateCellOwned(pub V03State); +pub struct LEEStateCellOwned(pub V03State); -impl SimpleStorableCell for NSSAStateCellOwned { +impl SimpleStorableCell for LEEStateCellOwned { type KeyParams = (); - const CELL_NAME: &'static str = DB_NSSA_STATE_KEY; - const CF_NAME: &'static str = CF_NSSA_STATE_NAME; + const CELL_NAME: &'static str = DB_LEE_STATE_KEY; + const CF_NAME: &'static str = CF_LEE_STATE_NAME; } -impl SimpleReadableCell for NSSAStateCellOwned {} +impl SimpleReadableCell for LEEStateCellOwned {} #[derive(BorshSerialize)] -pub struct NSSAStateCellRef<'state>(pub &'state V03State); +pub struct LEEStateCellRef<'state>(pub &'state V03State); -impl SimpleStorableCell for NSSAStateCellRef<'_> { +impl SimpleStorableCell for LEEStateCellRef<'_> { type KeyParams = (); - const CELL_NAME: &'static str = DB_NSSA_STATE_KEY; - const CF_NAME: &'static str = CF_NSSA_STATE_NAME; + const CELL_NAME: &'static str = DB_LEE_STATE_KEY; + const CF_NAME: &'static str = CF_LEE_STATE_NAME; } -impl SimpleWritableCell for NSSAStateCellRef<'_> { +impl SimpleWritableCell for LEEStateCellRef<'_> { fn value_constructor(&self) -> DbResult> { borsh::to_vec(&self).map_err(|err| { DbError::borsh_cast_message(err, Some("Failed to serialize last state".to_owned())) @@ -131,22 +132,66 @@ impl SimpleWritableCell for ZoneSdkCheckpointCellRef<'_> { } } +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] +pub struct PendingDepositEventRecord { + pub deposit_op_id: HashType, + pub source_tx_hash: HashType, + pub amount: u64, + pub metadata: Vec, + /// Set when block containing the deposit event is submitted, but not necessarily finalized. + pub submitted_in_block_id: Option, +} + +#[derive(BorshDeserialize)] +pub struct PendingDepositEventsCellOwned(pub Vec); + +impl SimpleStorableCell for PendingDepositEventsCellOwned { + type KeyParams = (); + + const CELL_NAME: &'static str = DB_META_PENDING_DEPOSIT_EVENTS_KEY; + const CF_NAME: &'static str = CF_META_NAME; +} + +impl SimpleReadableCell for PendingDepositEventsCellOwned {} + +#[derive(BorshSerialize)] +pub struct PendingDepositEventsCellRef<'records>(pub &'records [PendingDepositEventRecord]); + +impl SimpleStorableCell for PendingDepositEventsCellRef<'_> { + type KeyParams = (); + + const CELL_NAME: &'static str = DB_META_PENDING_DEPOSIT_EVENTS_KEY; + const CF_NAME: &'static str = CF_META_NAME; +} + +impl SimpleWritableCell for PendingDepositEventsCellRef<'_> { + fn value_constructor(&self) -> DbResult> { + borsh::to_vec(&self).map_err(|err| { + DbError::borsh_cast_message( + err, + Some("Failed to serialize pending deposit events cell".to_owned()), + ) + }) + } +} + #[cfg(test)] mod uniform_tests { use crate::{ cells::SimpleStorableCell as _, sequencer::sequencer_cells::{ - LatestBlockMetaCellOwned, LatestBlockMetaCellRef, NSSAStateCellOwned, NSSAStateCellRef, + LEEStateCellOwned, LEEStateCellRef, LatestBlockMetaCellOwned, LatestBlockMetaCellRef, + PendingDepositEventsCellOwned, PendingDepositEventsCellRef, }, }; #[test] fn state_ref_and_owned_is_aligned() { - assert_eq!(NSSAStateCellRef::CELL_NAME, NSSAStateCellOwned::CELL_NAME); - assert_eq!(NSSAStateCellRef::CF_NAME, NSSAStateCellOwned::CF_NAME); + assert_eq!(LEEStateCellRef::CELL_NAME, LEEStateCellOwned::CELL_NAME); + assert_eq!(LEEStateCellRef::CF_NAME, LEEStateCellOwned::CF_NAME); assert_eq!( - NSSAStateCellRef::key_constructor(()).unwrap(), - NSSAStateCellOwned::key_constructor(()).unwrap() + LEEStateCellRef::key_constructor(()).unwrap(), + LEEStateCellOwned::key_constructor(()).unwrap() ); } @@ -165,4 +210,20 @@ mod uniform_tests { LatestBlockMetaCellOwned::key_constructor(()).unwrap() ); } + + #[test] + fn pending_deposit_events_ref_and_owned_is_aligned() { + assert_eq!( + PendingDepositEventsCellRef::CELL_NAME, + PendingDepositEventsCellOwned::CELL_NAME + ); + assert_eq!( + PendingDepositEventsCellRef::CF_NAME, + PendingDepositEventsCellOwned::CF_NAME + ); + assert_eq!( + PendingDepositEventsCellRef::key_constructor(()).unwrap(), + PendingDepositEventsCellOwned::key_constructor(()).unwrap() + ); + } } diff --git a/testnet_initial_state/Cargo.toml b/lez/testnet_initial_state/Cargo.toml similarity index 81% rename from testnet_initial_state/Cargo.toml rename to lez/testnet_initial_state/Cargo.toml index 2b73f479..c2e694b4 100644 --- a/testnet_initial_state/Cargo.toml +++ b/lez/testnet_initial_state/Cargo.toml @@ -6,8 +6,8 @@ license.workspace = true [dependencies] key_protocol.workspace = true -nssa.workspace = true -nssa_core.workspace = true +lee.workspace = true +lee_core.workspace = true common.workspace = true serde.workspace = true diff --git a/testnet_initial_state/src/lib.rs b/lez/testnet_initial_state/src/lib.rs similarity index 83% rename from testnet_initial_state/src/lib.rs rename to lez/testnet_initial_state/src/lib.rs index 668d5f24..5bb6e1b4 100644 --- a/testnet_initial_state/src/lib.rs +++ b/lez/testnet_initial_state/src/lib.rs @@ -2,10 +2,10 @@ use common::PINATA_BASE58; use key_protocol::key_management::{ KeyChain, key_tree::chain_index::ChainIndex, - secret_holders::{PrivateKeyHolder, SecretSpendingKey}, + secret_holders::{PrivateKeyHolder, SecretSpendingKey, ViewingSecretKey}, }; -use nssa::{Account, AccountId, Data, PrivateKey, PublicKey, V03State}; -use nssa_core::{NullifierPublicKey, encryption::shared_key_derivation::Secp256k1Point}; +use lee::{Account, AccountId, Data, PrivateKey, PublicKey, V03State}; +use lee_core::{NullifierPublicKey, encryption::ViewingPublicKey}; use serde::{Deserialize, Serialize}; const PRIVATE_KEY_PUB_ACC_A: [u8; 32] = [ @@ -38,24 +38,24 @@ const NSK_PRIV_ACC_B: [u8; 32] = [ 23, 99, 9, 4, 177, 230, 125, 109, 91, 160, 30, ]; -const VSK_PRIV_ACC_A: [u8; 32] = [ - 5, 85, 114, 119, 141, 187, 202, 170, 122, 253, 198, 81, 150, 8, 155, 21, 192, 65, 24, 124, 116, - 98, 110, 106, 137, 90, 165, 239, 80, 13, 222, 30, +const VSK_D_PRIV_ACC_A: [u8; 32] = [ + 255, 250, 140, 26, 222, 223, 174, 95, 132, 108, 124, 88, 30, 247, 82, 72, 52, 70, 84, 139, 241, + 187, 41, 163, 19, 231, 232, 122, 225, 55, 134, 184, ]; -const VSK_PRIV_ACC_B: [u8; 32] = [ - 205, 32, 76, 251, 255, 236, 96, 119, 61, 111, 65, 100, 75, 218, 12, 22, 17, 170, 55, 226, 21, - 154, 161, 34, 208, 74, 27, 1, 119, 13, 88, 128, +const VSK_Z_PRIV_ACC_A: [u8; 32] = [ + 225, 24, 98, 78, 31, 203, 175, 248, 213, 17, 133, 207, 10, 135, 132, 151, 59, 184, 5, 81, 28, + 238, 137, 62, 233, 227, 99, 17, 236, 159, 244, 63, ]; -const VPK_PRIV_ACC_A: [u8; 33] = [ - 2, 210, 206, 38, 213, 4, 182, 198, 220, 47, 93, 148, 61, 84, 148, 250, 158, 45, 8, 81, 48, 80, - 46, 230, 87, 210, 47, 204, 76, 58, 214, 167, 81, +const VSK_D_PRIV_ACC_B: [u8; 32] = [ + 128, 85, 85, 103, 226, 218, 119, 56, 60, 252, 31, 113, 232, 215, 156, 2, 159, 247, 156, 192, + 12, 178, 229, 236, 255, 120, 146, 211, 169, 117, 153, 180, ]; -const VPK_PRIV_ACC_B: [u8; 33] = [ - 2, 79, 110, 46, 203, 29, 206, 205, 18, 86, 27, 189, 104, 103, 113, 181, 110, 53, 78, 172, 11, - 171, 190, 18, 126, 214, 81, 77, 192, 154, 58, 195, 238, +const VSK_Z_PRIV_ACC_B: [u8; 32] = [ + 165, 80, 169, 87, 248, 88, 167, 154, 27, 67, 131, 122, 50, 130, 111, 40, 164, 180, 204, 75, + 188, 140, 110, 132, 113, 133, 222, 8, 49, 123, 187, 18, ]; const NPK_PRIV_ACC_A: [u8; 32] = [ @@ -84,28 +84,28 @@ pub struct PublicAccountPublicInitialData { #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct PrivateAccountPublicInitialData { - pub npk: nssa_core::NullifierPublicKey, - pub account: nssa_core::account::Account, + pub npk: lee_core::NullifierPublicKey, + pub account: lee_core::account::Account, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct PublicAccountPrivateInitialData { - pub account_id: nssa::AccountId, - pub pub_sign_key: nssa::PrivateKey, + pub account_id: lee::AccountId, + pub pub_sign_key: lee::PrivateKey, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct PrivateAccountPrivateInitialData { - pub account: nssa_core::account::Account, + pub account: lee_core::account::Account, pub key_chain: KeyChain, pub chain_index: Option, - pub identifier: nssa_core::Identifier, + pub identifier: lee_core::Identifier, } impl PrivateAccountPrivateInitialData { #[must_use] - pub fn account_id(&self) -> nssa::AccountId { - nssa::AccountId::for_regular_private_account( + pub fn account_id(&self) -> lee::AccountId { + lee::AccountId::for_regular_private_account( &self.key_chain.nullifier_public_key, self.identifier, ) @@ -136,20 +136,20 @@ pub fn initial_priv_accounts_private_keys() -> Vec Vec { #[must_use] pub fn initial_state() -> V03State { - let initial_private_accounts: Vec<(nssa_core::Commitment, nssa_core::Nullifier)> = + let initial_private_accounts: Vec<(lee_core::Commitment, lee_core::Nullifier)> = initial_commitments() .iter() .map(|init_comm_data| { let npk = &init_comm_data.npk; - let account_id = nssa::AccountId::for_regular_private_account(npk, 0); + let account_id = lee::AccountId::for_regular_private_account(npk, 0); let mut acc = init_comm_data.account.clone(); - acc.program_owner = nssa::program::Program::authenticated_transfer_program().id(); + acc.program_owner = lee::program::Program::authenticated_transfer_program().id(); ( - nssa_core::Commitment::new(&account_id, &acc), - nssa_core::Nullifier::for_account_initialization(&account_id), + lee_core::Commitment::new(&account_id, &acc), + lee_core::Nullifier::for_account_initialization(&account_id), ) }) .collect(); - let init_accs: Vec<(nssa::AccountId, u128)> = initial_accounts() + let init_accs: Vec<(lee::AccountId, u128)> = initial_accounts() .iter() .map(|acc_data| (acc_data.account_id, acc_data.balance)) .collect(); - nssa::V03State::new_with_genesis_accounts(&init_accs, initial_private_accounts, 0) + lee::V03State::new_with_genesis_accounts(&init_accs, initial_private_accounts, 0) } #[must_use] diff --git a/wallet-ffi/Cargo.toml b/lez/wallet-ffi/Cargo.toml similarity index 86% rename from wallet-ffi/Cargo.toml rename to lez/wallet-ffi/Cargo.toml index 869845c8..567ad27c 100644 --- a/wallet-ffi/Cargo.toml +++ b/lez/wallet-ffi/Cargo.toml @@ -12,8 +12,8 @@ crate-type = ["rlib", "cdylib", "staticlib"] [dependencies] wallet.workspace = true -nssa.workspace = true -nssa_core.workspace = true +lee.workspace = true +lee_core.workspace = true sequencer_service_rpc = { workspace = true, features = ["client"] } tokio.workspace = true @@ -28,4 +28,4 @@ tempfile = "3" [features] default = ["prove"] -prove = ["nssa/prove"] +prove = ["lee/prove"] diff --git a/wallet-ffi/build.rs b/lez/wallet-ffi/build.rs similarity index 100% rename from wallet-ffi/build.rs rename to lez/wallet-ffi/build.rs diff --git a/wallet-ffi/cbindgen.toml b/lez/wallet-ffi/cbindgen.toml similarity index 97% rename from wallet-ffi/cbindgen.toml rename to lez/wallet-ffi/cbindgen.toml index 42c46543..b7824ab4 100644 --- a/wallet-ffi/cbindgen.toml +++ b/lez/wallet-ffi/cbindgen.toml @@ -1,7 +1,7 @@ language = "C" header = """ /** - * NSSA Wallet FFI Bindings + * LEE Wallet FFI Bindings * * Thread Safety: All functions are thread-safe. The wallet handle can be * shared across threads, but operations are serialized internally. diff --git a/wallet-ffi/src/account.rs b/lez/wallet-ffi/src/account.rs similarity index 99% rename from wallet-ffi/src/account.rs rename to lez/wallet-ffi/src/account.rs index ed27abe6..fdbfabc1 100644 --- a/wallet-ffi/src/account.rs +++ b/lez/wallet-ffi/src/account.rs @@ -3,7 +3,7 @@ use std::{ffi::c_char, ptr, str::FromStr as _}; use key_protocol::key_management::{key_tree::chain_index::ChainIndex, KeyChain}; -use nssa::AccountId; +use lee::AccountId; use wallet::account::{AccountIdWithPrivacy, HumanReadableAccount}; use crate::{ @@ -517,7 +517,7 @@ pub unsafe extern "C" fn wallet_ffi_import_public_account( Err(e) => return e, }; - let private_key = match nssa::PrivateKey::from_str(&private_key_hex) { + let private_key = match lee::PrivateKey::from_str(&private_key_hex) { Ok(value) => value, Err(e) => { print_error(format!("Invalid public account private key: {e}")); @@ -609,7 +609,7 @@ pub unsafe extern "C" fn wallet_ffi_import_private_account( } }; - let account = nssa::Account::from(account_state); + let account = lee::Account::from(account_state); let mut wallet = match wrapper.core.lock() { Ok(w) => w, diff --git a/wallet-ffi/src/error.rs b/lez/wallet-ffi/src/error.rs similarity index 96% rename from wallet-ffi/src/error.rs rename to lez/wallet-ffi/src/error.rs index 17b73075..206f24d8 100644 --- a/wallet-ffi/src/error.rs +++ b/lez/wallet-ffi/src/error.rs @@ -37,7 +37,7 @@ pub enum WalletFfiError { SyncError = 13, /// Serialization/deserialization error. SerializationError = 14, - /// Invalid conversion from FFI types to NSSA types. + /// Invalid conversion from FFI types to LEE types. InvalidTypeConversion = 15, /// Invalid Key value. InvalidKeyValue = 16, diff --git a/wallet-ffi/src/keys.rs b/lez/wallet-ffi/src/keys.rs similarity index 98% rename from wallet-ffi/src/keys.rs rename to lez/wallet-ffi/src/keys.rs index b676ffab..1eae1723 100644 --- a/wallet-ffi/src/keys.rs +++ b/lez/wallet-ffi/src/keys.rs @@ -2,7 +2,7 @@ use std::ptr; -use nssa::{AccountId, PublicKey}; +use lee::{AccountId, PublicKey}; use crate::{ error::{print_error, WalletFfiError}, @@ -125,7 +125,7 @@ pub unsafe extern "C" fn wallet_ffi_get_private_account_keys( // NPK is a 32-byte array let npk_bytes = key_chain.nullifier_public_key.0; - // VPK is a compressed secp256k1 point (33 bytes) + // VPK is an ML-KEM-768 encapsulation key (1184 bytes) let vpk_bytes = key_chain.viewing_public_key.to_bytes(); let vpk_len = vpk_bytes.len(); let vpk_vec = vpk_bytes.to_vec(); diff --git a/wallet-ffi/src/lib.rs b/lez/wallet-ffi/src/lib.rs similarity index 96% rename from wallet-ffi/src/lib.rs rename to lez/wallet-ffi/src/lib.rs index 16943d3e..b28a548a 100644 --- a/wallet-ffi/src/lib.rs +++ b/lez/wallet-ffi/src/lib.rs @@ -1,6 +1,6 @@ -//! NSSA Wallet FFI Library. +//! LEE Wallet FFI Library. //! -//! This crate provides C-compatible bindings for the NSSA wallet functionality. +//! This crate provides C-compatible bindings for the LEE wallet functionality. //! //! # Usage //! diff --git a/wallet-ffi/src/pinata.rs b/lez/wallet-ffi/src/pinata.rs similarity index 99% rename from wallet-ffi/src/pinata.rs rename to lez/wallet-ffi/src/pinata.rs index 5807db7b..b1fdb27a 100644 --- a/wallet-ffi/src/pinata.rs +++ b/lez/wallet-ffi/src/pinata.rs @@ -2,8 +2,8 @@ use std::{ffi::CString, ptr, slice}; -use nssa::AccountId; -use nssa_core::MembershipProof; +use lee::AccountId; +use lee_core::MembershipProof; use wallet::program_facades::pinata::Pinata; use crate::{ diff --git a/wallet-ffi/src/sync.rs b/lez/wallet-ffi/src/sync.rs similarity index 100% rename from wallet-ffi/src/sync.rs rename to lez/wallet-ffi/src/sync.rs diff --git a/wallet-ffi/src/transfer.rs b/lez/wallet-ffi/src/transfer.rs similarity index 99% rename from wallet-ffi/src/transfer.rs rename to lez/wallet-ffi/src/transfer.rs index a5cbeef0..1fcd3133 100644 --- a/wallet-ffi/src/transfer.rs +++ b/lez/wallet-ffi/src/transfer.rs @@ -5,7 +5,7 @@ use std::{ ptr, }; -use nssa::AccountId; +use lee::AccountId; use wallet::{ account::AccountIdWithPrivacy, cli::CliAccountMention, program_facades::native_token_transfer::NativeTokenTransfer, AccountIdentity, diff --git a/wallet-ffi/src/types.rs b/lez/wallet-ffi/src/types.rs similarity index 82% rename from wallet-ffi/src/types.rs rename to lez/wallet-ffi/src/types.rs index b970a8d3..8c9e105d 100644 --- a/wallet-ffi/src/types.rs +++ b/lez/wallet-ffi/src/types.rs @@ -3,8 +3,7 @@ use core::slice; use std::{ffi::c_char, ptr}; -use nssa::Data; -use nssa_core::encryption::shared_key_derivation::Secp256k1Point; +use lee::Data; use crate::error::WalletFfiError; @@ -38,7 +37,7 @@ pub struct FfiU128 { pub data: [u8; 16], } -/// Account data structure - C-compatible version of nssa Account. +/// Account data structure - C-compatible version of lee Account. /// /// Note: `balance` and `nonce` are u128 values represented as little-endian /// byte arrays since C doesn't have native u128 support. @@ -72,9 +71,9 @@ impl Default for FfiAccount { pub struct FfiPrivateAccountKeys { /// Nullifier public key (32 bytes). pub nullifier_public_key: FfiBytes32, - /// viewing public key (compressed secp256k1 point). + /// Viewing public key (ML-KEM-768 encapsulation key, 1184 bytes). pub viewing_public_key: *const u8, - /// Length of viewing public key (typically 33 bytes). + /// Length of viewing public key (always 1184 bytes for ML-KEM-768). pub viewing_public_key_len: usize, } @@ -149,23 +148,26 @@ impl FfiBytes32 { /// Create from an `AccountId`. #[must_use] - pub const fn from_account_id(id: nssa::AccountId) -> Self { + pub const fn from_account_id(id: lee::AccountId) -> Self { Self { data: *id.value() } } } impl FfiPrivateAccountKeys { #[must_use] - pub const fn npk(&self) -> nssa_core::NullifierPublicKey { - nssa_core::NullifierPublicKey(self.nullifier_public_key.data) + pub const fn npk(&self) -> lee_core::NullifierPublicKey { + lee_core::NullifierPublicKey(self.nullifier_public_key.data) } - pub fn vpk(&self) -> Result { - if self.viewing_public_key_len == 33 { + pub fn vpk(&self) -> Result { + if self.viewing_public_key_len == 1184 { let slice = unsafe { slice::from_raw_parts(self.viewing_public_key, self.viewing_public_key_len) }; - Ok(Secp256k1Point(slice.to_vec())) + Ok( + lee_core::encryption::ViewingPublicKey::from_bytes(slice.to_vec()) + .expect("wallet_ffi: length already validated to 1184 bytes"), + ) } else { Err(WalletFfiError::InvalidKeyValue) } @@ -186,24 +188,24 @@ impl From for u128 { } } -impl From for FfiBytes32 { - fn from(id: nssa::AccountId) -> Self { +impl From for FfiBytes32 { + fn from(id: lee::AccountId) -> Self { Self::from_account_id(id) } } -impl From for nssa::AccountId { +impl From for lee::AccountId { fn from(bytes: FfiBytes32) -> Self { Self::new(bytes.data) } } -impl From for FfiAccount { +impl From for FfiAccount { #[expect( clippy::as_conversions, reason = "We need to convert to byte arrays for FFI" )] - fn from(value: nssa::Account) -> Self { + fn from(value: lee::Account) -> Self { // Convert account data to FFI type let data_vec: Vec = value.data.into(); let data_len = data_vec.len(); @@ -227,7 +229,7 @@ impl From for FfiAccount { } } -impl TryFrom<&FfiAccount> for nssa::Account { +impl TryFrom<&FfiAccount> for lee::Account { type Error = WalletFfiError; fn try_from(value: &FfiAccount) -> Result { @@ -244,20 +246,20 @@ impl TryFrom<&FfiAccount> for nssa::Account { program_owner: value.program_owner.data, balance: value.balance.into(), data, - nonce: nssa_core::account::Nonce(value.nonce.into()), + nonce: lee_core::account::Nonce(value.nonce.into()), }) } } -impl From for FfiPublicAccountKey { - fn from(value: nssa::PublicKey) -> Self { +impl From for FfiPublicAccountKey { + fn from(value: lee::PublicKey) -> Self { Self { public_key: FfiBytes32::from_bytes(*value.value()), } } } -impl TryFrom<&FfiPublicAccountKey> for nssa::PublicKey { +impl TryFrom<&FfiPublicAccountKey> for lee::PublicKey { type Error = WalletFfiError; fn try_from(value: &FfiPublicAccountKey) -> Result { diff --git a/wallet-ffi/src/wallet.rs b/lez/wallet-ffi/src/wallet.rs similarity index 100% rename from wallet-ffi/src/wallet.rs rename to lez/wallet-ffi/src/wallet.rs diff --git a/wallet-ffi/wallet_ffi.h b/lez/wallet-ffi/wallet_ffi.h similarity index 99% rename from wallet-ffi/wallet_ffi.h rename to lez/wallet-ffi/wallet_ffi.h index 693e2d5c..512b3b96 100644 --- a/wallet-ffi/wallet_ffi.h +++ b/lez/wallet-ffi/wallet_ffi.h @@ -1,5 +1,5 @@ /** - * NSSA Wallet FFI Bindings + * LEE Wallet FFI Bindings * * Thread Safety: All functions are thread-safe. The wallet handle can be * shared across threads, but operations are serialized internally. @@ -24,7 +24,7 @@ #ifndef WALLET_FFI_H #define WALLET_FFI_H -/* Generated with cbindgen:0.29.2 */ +/* Generated with cbindgen:0.29.3 */ #include #include @@ -96,7 +96,7 @@ typedef enum WalletFfiError { */ SERIALIZATION_ERROR = 14, /** - * Invalid conversion from FFI types to NSSA types. + * Invalid conversion from FFI types to LEE types. */ INVALID_TYPE_CONVERSION = 15, /** @@ -135,11 +135,11 @@ typedef struct FfiPrivateAccountKeys { */ struct FfiBytes32 nullifier_public_key; /** - * viewing public key (compressed secp256k1 point). + * Viewing public key (ML-KEM-768 encapsulation key, 1184 bytes). */ const uint8_t *viewing_public_key; /** - * Length of viewing public key (typically 33 bytes). + * Length of viewing public key (always 1184 bytes for ML-KEM-768). */ uintptr_t viewing_public_key_len; } FfiPrivateAccountKeys; @@ -175,7 +175,7 @@ typedef struct FfiU128 { } FfiU128; /** - * Account data structure - C-compatible version of nssa Account. + * Account data structure - C-compatible version of lee Account. * * Note: `balance` and `nonce` are u128 values represented as little-endian * byte arrays since C doesn't have native u128 support. diff --git a/wallet/Cargo.toml b/lez/wallet/Cargo.toml similarity index 96% rename from wallet/Cargo.toml rename to lez/wallet/Cargo.toml index c8ccd3ef..40222715 100644 --- a/wallet/Cargo.toml +++ b/lez/wallet/Cargo.toml @@ -8,8 +8,8 @@ license = { workspace = true } workspace = true [dependencies] -nssa_core.workspace = true -nssa.workspace = true +lee_core.workspace = true +lee.workspace = true common.workspace = true authenticated_transfer_core.workspace = true key_protocol.workspace = true diff --git a/wallet/configs/debug/wallet_config.json b/lez/wallet/configs/debug/wallet_config.json similarity index 100% rename from wallet/configs/debug/wallet_config.json rename to lez/wallet/configs/debug/wallet_config.json diff --git a/wallet/src/account.rs b/lez/wallet/src/account.rs similarity index 93% rename from wallet/src/account.rs rename to lez/wallet/src/account.rs index dca0a051..64eee575 100644 --- a/wallet/src/account.rs +++ b/lez/wallet/src/account.rs @@ -2,7 +2,7 @@ use std::str::FromStr; use base58::{FromBase58 as _, ToBase58 as _}; use derive_more::Display; -use nssa::AccountId; +use lee::AccountId; use serde::{Deserialize, Serialize}; use thiserror::Error; @@ -54,7 +54,7 @@ pub enum AccountIdWithPrivacyParseError { #[error("Invalid format, expected 'Public/{{account_id}}' or 'Private/{{account_id}}'")] InvalidFormat, #[error("Invalid account id")] - InvalidAccountId(#[from] nssa_core::account::AccountIdError), + InvalidAccountId(#[from] lee_core::account::AccountIdError), } impl FromStr for AccountIdWithPrivacy { @@ -95,8 +95,8 @@ impl std::fmt::Display for HumanReadableAccount { } } -impl From for HumanReadableAccount { - fn from(account: nssa::Account) -> Self { +impl From for HumanReadableAccount { + fn from(account: lee::Account) -> Self { let program_owner = account .program_owner .iter() @@ -113,7 +113,7 @@ impl From for HumanReadableAccount { } } -impl From for nssa::Account { +impl From for lee::Account { fn from(account: HumanReadableAccount) -> Self { let mut program_owner_bytes = [0_u8; 32]; let decoded_program_owner = account @@ -143,7 +143,7 @@ impl From for nssa::Account { balance: account.balance, program_owner, data, - nonce: nssa_core::account::Nonce(account.nonce), + nonce: lee_core::account::Nonce(account.nonce), } } } diff --git a/wallet/src/account_manager.rs b/lez/wallet/src/account_manager.rs similarity index 94% rename from wallet/src/account_manager.rs rename to lez/wallet/src/account_manager.rs index f8d8bcbe..46e9bcaa 100644 --- a/wallet/src/account_manager.rs +++ b/lez/wallet/src/account_manager.rs @@ -1,8 +1,8 @@ use anyhow::Result; use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; use keycard_wallet::{KeycardWallet, python_path}; -use nssa::{AccountId, PrivateKey, PublicKey, Signature}; -use nssa_core::{ +use lee::{AccountId, PrivateKey, PublicKey, Signature}; +use lee_core::{ Identifier, InputAccountIdentity, MembershipProof, NullifierPublicKey, NullifierSecretKey, SharedSecretKey, account::{AccountWithMetadata, Nonce}, @@ -194,11 +194,11 @@ impl AccountManager { vpk, identifier, } => { - let acc = nssa_core::account::Account::default(); + let acc = lee_core::account::Account::default(); let auth_acc = AccountWithMetadata::new(acc, false, (&npk, identifier)); - let eph_holder = EphemeralKeyHolder::new(&npk); - let ssk = eph_holder.calculate_shared_secret_sender(&vpk); - let epk = eph_holder.generate_ephemeral_public_key(); + let eph_holder = EphemeralKeyHolder::new(&vpk); + let ssk = eph_holder.calculate_shared_secret_sender(); + let epk = eph_holder.ephemeral_public_key().clone(); let pre = AccountPreparedData { nsk: None, npk, @@ -223,11 +223,11 @@ impl AccountManager { vpk, identifier, } => { - let acc = nssa_core::account::Account::default(); + let acc = lee_core::account::Account::default(); let auth_acc = AccountWithMetadata::new(acc, false, account_id); - let eph_holder = EphemeralKeyHolder::new(&npk); - let ssk = eph_holder.calculate_shared_secret_sender(&vpk); - let epk = eph_holder.generate_ephemeral_public_key(); + let eph_holder = EphemeralKeyHolder::new(&vpk); + let ssk = eph_holder.calculate_shared_secret_sender(); + let epk = eph_holder.ephemeral_public_key().clone(); let pre = AccountPreparedData { nsk: None, npk, @@ -247,7 +247,7 @@ impl AccountManager { vpk, identifier, } => { - let account_id = nssa::AccountId::from((&npk, identifier)); + let account_id = lee::AccountId::from((&npk, identifier)); let pre = private_shared_acc_preparation( wallet, account_id, nsk, npk, vpk, identifier, false, ) @@ -471,9 +471,9 @@ async fn private_key_tree_acc_preparation( // support from that in the wallet. let sender_pre = AccountWithMetadata::new(from_acc.account.clone(), true, account_id); - let eph_holder = EphemeralKeyHolder::new(&from_npk); - let ssk = eph_holder.calculate_shared_secret_sender(&from_vpk); - let epk = eph_holder.generate_ephemeral_public_key(); + let eph_holder = EphemeralKeyHolder::new(&from_vpk); + let ssk = eph_holder.calculate_shared_secret_sender(); + let epk = eph_holder.ephemeral_public_key().clone(); Ok(AccountPreparedData { nsk: Some(nsk), @@ -511,9 +511,10 @@ async fn private_shared_acc_preparation( .await .unwrap_or(None); - let eph_holder = EphemeralKeyHolder::new(&npk); - let ssk = eph_holder.calculate_shared_secret_sender(&vpk); - let epk = eph_holder.generate_ephemeral_public_key(); + let eph_holder = EphemeralKeyHolder::new(&vpk); + let ssk = eph_holder.calculate_shared_secret_sender(); + let epk = eph_holder.ephemeral_public_key().clone(); + Ok(AccountPreparedData { nsk: Some(nsk), npk, @@ -536,7 +537,7 @@ mod tests { let acc = AccountIdentity::PrivateShared { nsk: [0; 32], npk: NullifierPublicKey([1; 32]), - vpk: ViewingPublicKey::from_scalar([2; 32]), + vpk: ViewingPublicKey::from_seed(&[2_u8; 32], &[3_u8; 32]), identifier: 42, }; assert!(acc.is_private()); diff --git a/wallet/src/cli/account.rs b/lez/wallet/src/cli/account.rs similarity index 90% rename from wallet/src/cli/account.rs rename to lez/wallet/src/cli/account.rs index 97bbd095..e0ec2d0f 100644 --- a/wallet/src/cli/account.rs +++ b/lez/wallet/src/cli/account.rs @@ -2,8 +2,8 @@ use anyhow::{Context as _, Result}; use clap::Subcommand; use itertools::Itertools as _; use key_protocol::key_management::{KeyChain, key_tree::chain_index::ChainIndex}; -use nssa::{Account, PublicKey, program::Program}; -use nssa_core::Identifier; +use lee::{Account, PublicKey, program::Program}; +use lee_core::Identifier; use token_core::{TokenDefinition, TokenHolding}; use crate::{ @@ -57,6 +57,20 @@ pub enum AccountSubcommand { /// Import external account. #[command(subcommand)] Import(ImportSubcommand), + /// Print the npk and vpk for a private account, one per line. + /// + /// Outputs two lines: npk (hex) then vpk (hex). Save to a file and share it + /// with senders so they can reference it with `--to-keys /path/to/file`. + /// + /// ```text + /// wallet account show-keys --account-id Private/... > alice.keys + /// ``` + #[command(name = "show-keys")] + ShowKeys { + /// Either 32 byte base58 account id string with privacy prefix or a label. + #[arg(long)] + account_id: CliAccountMention, + }, } /// Represents generic register CLI subcommand. @@ -201,13 +215,13 @@ impl WalletSubcommand for NewSubcommand { .context("Invalid seed hex")? .try_into() .map_err(|_err| anyhow::anyhow!("Seed must be exactly 32 bytes"))?; - let pda_seed = nssa_core::program::PdaSeed::new(seed_bytes); + let pda_seed = lee_core::program::PdaSeed::new(seed_bytes); let pid_bytes = hex::decode(&pid_hex).context("Invalid program ID hex")?; if pid_bytes.len() != 32 { anyhow::bail!("Program ID must be exactly 32 bytes"); } - let mut pid: nssa_core::program::ProgramId = [0; 8]; + let mut pid: lee_core::program::ProgramId = [0; 8]; for (i, chunk) in pid_bytes.chunks_exact(4).enumerate() { pid[i] = u32::from_le_bytes(chunk.try_into().unwrap()); } @@ -231,7 +245,7 @@ impl WalletSubcommand for NewSubcommand { println!("Shared account from group '{group}'"); println!("AccountId: Private/{}", info.account_id); println!("NPK: {}", hex::encode(info.npk.0)); - println!("VPK: {}", hex::encode(&info.vpk.0)); + println!("VPK: {}", hex::encode(info.vpk.to_bytes())); wallet_core.store_persistent_data()?; Ok(SubcommandReturnValue::RegisterAccount { @@ -433,6 +447,25 @@ impl WalletSubcommand for AccountSubcommand { Self::Import(import_subcommand) => { import_subcommand.handle_subcommand(wallet_core).await } + Self::ShowKeys { account_id } => { + let resolved = account_id.resolve(wallet_core.storage())?; + let AccountIdWithPrivacy::Private(account_id) = resolved else { + anyhow::bail!( + "wallet::cli::account::AccountSubcommand::ShowKeys: show-keys is only available for private accounts" + ); + }; + let entry = wallet_core + .storage() + .key_chain() + .private_account(account_id) + .ok_or_else(|| anyhow::anyhow!("wallet::cli::account::AccountSubcommand::ShowKeys: private account not found in wallet"))?; + println!("{}", hex::encode(entry.key_chain.nullifier_public_key.0)); + println!( + "{}", + hex::encode(entry.key_chain.viewing_public_key.to_bytes()) + ); + Ok(SubcommandReturnValue::Empty) + } } } } @@ -443,7 +476,7 @@ pub enum ImportSubcommand { Public { /// Private key in hex format. #[arg(long)] - private_key: nssa::PrivateKey, + private_key: lee::PrivateKey, }, /// Import a private account keychain and account state. Private { @@ -470,7 +503,7 @@ impl WalletSubcommand for ImportSubcommand { match self { Self::Public { private_key } => { let account_id = - nssa::AccountId::from(&nssa::PublicKey::new_from_private_key(&private_key)); + lee::AccountId::from(&lee::PublicKey::new_from_private_key(&private_key)); wallet_core .storage_mut() @@ -491,9 +524,9 @@ impl WalletSubcommand for ImportSubcommand { } => { let key_chain: KeyChain = serde_json::from_str(&key_chain_json) .map_err(|err| anyhow::anyhow!("Invalid key chain JSON: {err}"))?; - let account = nssa::Account::from(account_state); + let account = lee::Account::from(account_state); let account_id = - nssa::AccountId::from((&key_chain.nullifier_public_key, identifier)); + lee::AccountId::from((&key_chain.nullifier_public_key, identifier)); wallet_core .storage_mut() diff --git a/wallet/src/cli/chain.rs b/lez/wallet/src/cli/chain.rs similarity index 100% rename from wallet/src/cli/chain.rs rename to lez/wallet/src/cli/chain.rs diff --git a/wallet/src/cli/config.rs b/lez/wallet/src/cli/config.rs similarity index 100% rename from wallet/src/cli/config.rs rename to lez/wallet/src/cli/config.rs diff --git a/wallet/src/cli/group.rs b/lez/wallet/src/cli/group.rs similarity index 90% rename from wallet/src/cli/group.rs rename to lez/wallet/src/cli/group.rs index 987f7a3a..a4bb12c9 100644 --- a/wallet/src/cli/group.rs +++ b/lez/wallet/src/cli/group.rs @@ -1,6 +1,9 @@ use anyhow::{Context as _, Result}; use clap::Subcommand; -use key_protocol::key_management::group_key_holder::{GroupKeyHolder, SealingPublicKey}; +use key_protocol::key_management::{ + group_key_holder::{GroupKeyHolder, SealingPublicKey}, + secret_holders::ViewingSecretKey, +}; use crate::{ WalletCore, @@ -149,9 +152,15 @@ impl WalletSubcommand for GroupSubcommand { anyhow::bail!("Sealing key already exists. Each wallet has one sealing key."); } - let mut secret: nssa_core::encryption::Scalar = [0_u8; 32]; - rand::RngCore::fill_bytes(&mut rand::rngs::OsRng, &mut secret); - let public_key = SealingPublicKey::from_scalar(secret); + let mut d = [0_u8; 32]; + let mut r = [0_u8; 32]; + rand::RngCore::fill_bytes(&mut rand::rngs::OsRng, &mut d); + rand::RngCore::fill_bytes(&mut rand::rngs::OsRng, &mut r); + let secret = ViewingSecretKey::new(d, r); + let ek_bytes = lee_core::encryption::ViewingPublicKey::from_seed(&d, &r) + .to_bytes() + .to_vec(); + let public_key = SealingPublicKey::from_bytes(ek_bytes); wallet_core.set_sealing_secret_key(secret); wallet_core.store_persistent_data()?; diff --git a/wallet/src/cli/keycard.rs b/lez/wallet/src/cli/keycard.rs similarity index 100% rename from wallet/src/cli/keycard.rs rename to lez/wallet/src/cli/keycard.rs diff --git a/wallet/src/cli/mod.rs b/lez/wallet/src/cli/mod.rs similarity index 74% rename from wallet/src/cli/mod.rs rename to lez/wallet/src/cli/mod.rs index 5f0fcb44..c7a70ecd 100644 --- a/wallet/src/cli/mod.rs +++ b/lez/wallet/src/cli/mod.rs @@ -3,10 +3,10 @@ use std::{io::Write as _, path::PathBuf, str::FromStr}; use anyhow::{Context as _, Result}; use bip39::Mnemonic; use clap::{Parser, Subcommand}; -use common::{HashType, transaction::NSSATransaction}; +use common::{HashType, transaction::LeeTransaction}; use derive_more::Display; use futures::TryFutureExt as _; -use nssa::{ProgramDeploymentTransaction, program::Program}; +use lee::{ProgramDeploymentTransaction, program::Program}; use sequencer_service_rpc::RpcClient as _; pub use crate::helperfunctions::{read_mnemonic, read_pin}; @@ -89,7 +89,7 @@ pub enum Command { Keycard(KeycardSubcommand), } -/// To execute commands, env var `NSSA_WALLET_HOME_DIR` must be set into directory with config. +/// To execute commands, env var `LEE_WALLET_HOME_DIR` must be set into directory with config. /// /// All account addresses must be valid 32 byte base58 strings. /// @@ -112,8 +112,8 @@ pub struct Args { #[derive(Debug, Clone)] pub enum SubcommandReturnValue { PrivacyPreservingTransfer { tx_hash: HashType }, - RegisterAccount { account_id: nssa::AccountId }, - Account(nssa::Account), + RegisterAccount { account_id: lee::AccountId }, + Account(lee::Account), Empty, SyncedToBlock(u64), } @@ -236,7 +236,7 @@ pub async fn execute_subcommand( panic!("Missing privacy preserving circuit ID from remote"); }; assert!( - circuit_id == &nssa::PRIVACY_PRESERVING_CIRCUIT_ID, + circuit_id == &lee::PRIVACY_PRESERVING_CIRCUIT_ID, "Local ID for privacy preserving circuit is different from remote" ); let Some(amm_id) = remote_program_ids.get("amm") else { @@ -274,11 +274,11 @@ pub async fn execute_subcommand( "Failed to read program binary at {}", binary_filepath.display() ))?; - let message = nssa::program_deployment_transaction::Message::new(bytecode); + let message = lee::program_deployment_transaction::Message::new(bytecode); let transaction = ProgramDeploymentTransaction::new(message); let _response = wallet_core .sequencer_client - .send_transaction(NSSATransaction::ProgramDeployment(transaction)) + .send_transaction(LeeTransaction::ProgramDeployment(transaction)) .await .context("Transaction submission error")?; @@ -306,6 +306,31 @@ pub fn read_password_from_stdin() -> Result { Ok(password.trim().to_owned()) } +/// Parse a keys file exported by `wallet account show-keys`. +/// +/// The file format is two lines: +/// - Line 1: npk as hex (64 chars, 32 bytes). +/// - Line 2: vpk as hex (2368 chars, 1184 bytes). +/// +/// Returns `(npk_bytes, vpk_bytes)`. +pub fn read_keys_file(path: &str) -> Result<(Vec, Vec)> { + let content = std::fs::read_to_string(path).with_context(|| { + format!("wallet::cli::read_keys_file: failed to read keys file: {path}") + })?; + let mut lines = content.lines().filter(|l| !l.trim().is_empty()); + let npk_hex = lines.next().ok_or_else(|| { + anyhow::anyhow!("wallet::cli::read_keys_file: keys file is missing npk (line 1)") + })?; + let vpk_hex = lines.next().ok_or_else(|| { + anyhow::anyhow!("wallet::cli::read_keys_file: keys file is missing vpk (line 2)") + })?; + let npk = hex::decode(npk_hex.trim()) + .context("wallet::cli::read_keys_file: npk in keys file must be valid hex")?; + let vpk = hex::decode(vpk_hex.trim()) + .context("wallet::cli::read_keys_file: vpk in keys file must be valid hex")?; + Ok((npk, vpk)) +} + pub fn read_mnemonic_from_stdin() -> Result { let mut phrase = String::new(); @@ -349,3 +374,77 @@ pub async fn execute_keys_restoration(wallet_core: &mut WalletCore, depth: u32) Ok(()) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn read_keys_file_roundtrip() { + let npk = [0xab_u8; 32]; + let vpk = [0xcd_u8; 1184]; + + let dir = tempfile::tempdir().unwrap(); + let path = dir.path().join("test.keys"); + + // Simulate what `wallet account show-keys` writes. + std::fs::write( + &path, + format!("{}\n{}\n", hex::encode(npk), hex::encode(vpk)), + ) + .unwrap(); + + let (parsed_npk, parsed_vpk) = read_keys_file(path.to_str().unwrap()).unwrap(); + + assert_eq!(parsed_npk, npk, "npk must round-trip through the keys file"); + assert_eq!( + parsed_vpk, + vpk.to_vec(), + "vpk must round-trip through the keys file" + ); + } + + #[test] + fn read_keys_file_missing_vpk_returns_error() { + let dir = tempfile::tempdir().unwrap(); + let path = dir.path().join("incomplete.keys"); + std::fs::write(&path, format!("{}\n", hex::encode([0xab_u8; 32]))).unwrap(); + + let result = read_keys_file(path.to_str().unwrap()); + assert!(result.is_err(), "missing vpk line must return an error"); + assert!( + result.unwrap_err().to_string().contains("missing vpk"), + "error must mention missing vpk" + ); + } + + #[test] + fn read_keys_file_invalid_hex_returns_error() { + let dir = tempfile::tempdir().unwrap(); + let path = dir.path().join("badhex.keys"); + std::fs::write(&path, "not-hex\nalso-not-hex\n").unwrap(); + + let result = read_keys_file(path.to_str().unwrap()); + assert!(result.is_err(), "invalid hex must return an error"); + } + + #[test] + fn read_keys_file_ignores_blank_lines() { + let npk = [0x11_u8; 32]; + let vpk = [0x22_u8; 1184]; + + let dir = tempfile::tempdir().unwrap(); + let path = dir.path().join("blanks.keys"); + + // Extra blank lines around the data should be tolerated. + std::fs::write( + &path, + format!("\n{}\n\n{}\n\n", hex::encode(npk), hex::encode(vpk)), + ) + .unwrap(); + + let (parsed_npk, parsed_vpk) = read_keys_file(path.to_str().unwrap()).unwrap(); + assert_eq!(parsed_npk, npk); + assert_eq!(parsed_vpk, vpk.to_vec()); + } +} diff --git a/wallet/src/cli/programs/amm.rs b/lez/wallet/src/cli/programs/amm.rs similarity index 99% rename from wallet/src/cli/programs/amm.rs rename to lez/wallet/src/cli/programs/amm.rs index 1ef4fdba..6cdeb07c 100644 --- a/wallet/src/cli/programs/amm.rs +++ b/lez/wallet/src/cli/programs/amm.rs @@ -1,6 +1,6 @@ use anyhow::Result; use clap::Subcommand; -use nssa::AccountId; +use lee::AccountId; use crate::{ WalletCore, diff --git a/wallet/src/cli/programs/ata.rs b/lez/wallet/src/cli/programs/ata.rs similarity index 96% rename from wallet/src/cli/programs/ata.rs rename to lez/wallet/src/cli/programs/ata.rs index 1b9b9428..b77ff61f 100644 --- a/wallet/src/cli/programs/ata.rs +++ b/lez/wallet/src/cli/programs/ata.rs @@ -1,7 +1,7 @@ use anyhow::Result; use clap::Subcommand; -use common::transaction::NSSATransaction; -use nssa::{Account, AccountId, program::Program}; +use common::transaction::LeeTransaction; +use lee::{Account, AccountId, program::Program}; use token_core::TokenHolding; use crate::{ @@ -113,7 +113,7 @@ impl WalletSubcommand for AtaSubcommand { println!("Transaction hash is {tx_hash}"); let tx = wallet_core.poll_native_token_transfer(tx_hash).await?; - if let NSSATransaction::PrivacyPreserving(tx) = tx { + if let LeeTransaction::PrivacyPreserving(tx) = tx { wallet_core.decode_insert_privacy_preserving_transaction_results( &tx, &[Decode(secret, owner_id)], @@ -159,7 +159,7 @@ impl WalletSubcommand for AtaSubcommand { println!("Transaction hash is {tx_hash}"); let tx = wallet_core.poll_native_token_transfer(tx_hash).await?; - if let NSSATransaction::PrivacyPreserving(tx) = tx { + if let LeeTransaction::PrivacyPreserving(tx) = tx { wallet_core.decode_insert_privacy_preserving_transaction_results( &tx, &[Decode(secret, from_id)], @@ -202,7 +202,7 @@ impl WalletSubcommand for AtaSubcommand { println!("Transaction hash is {tx_hash}"); let tx = wallet_core.poll_native_token_transfer(tx_hash).await?; - if let NSSATransaction::PrivacyPreserving(tx) = tx { + if let LeeTransaction::PrivacyPreserving(tx) = tx { wallet_core.decode_insert_privacy_preserving_transaction_results( &tx, &[Decode(secret, holder_id)], diff --git a/wallet/src/cli/programs/mod.rs b/lez/wallet/src/cli/programs/mod.rs similarity index 100% rename from wallet/src/cli/programs/mod.rs rename to lez/wallet/src/cli/programs/mod.rs diff --git a/wallet/src/cli/programs/native_token_transfer.rs b/lez/wallet/src/cli/programs/native_token_transfer.rs similarity index 88% rename from wallet/src/cli/programs/native_token_transfer.rs rename to lez/wallet/src/cli/programs/native_token_transfer.rs index c20c2726..eba1da0c 100644 --- a/wallet/src/cli/programs/native_token_transfer.rs +++ b/lez/wallet/src/cli/programs/native_token_transfer.rs @@ -1,7 +1,7 @@ -use anyhow::Result; +use anyhow::{Context as _, Result}; use clap::Subcommand; -use common::transaction::NSSATransaction; -use nssa::AccountId; +use common::transaction::LeeTransaction; +use lee::AccountId; use crate::{ AccDecodeData::Decode, @@ -34,13 +34,17 @@ pub enum AuthTransferSubcommand { #[arg(long)] to: Option, /// `to_npk` - valid 32 byte hex string. - #[arg(long)] + #[arg(long, conflicts_with = "to_keys")] to_npk: Option, - /// `to_vpk` - valid 33 byte hex string. - #[arg(long)] + /// `to_vpk` - valid hex-encoded ML-KEM-768 encapsulation key (1184 bytes). + #[arg(long, conflicts_with = "to_keys")] to_vpk: Option, + /// Path to a keys file exported by `wallet account show-keys`, containing npk + /// and vpk on separate lines. Replaces `--to-npk` and `--to-vpk`. + #[arg(long, conflicts_with_all = ["to_npk", "to_vpk"])] + to_keys: Option, /// Identifier for the recipient's private account (only used when sending to a foreign - /// private account via `--to-npk`/`--to-vpk`). + /// private account via `--to-npk`/`--to-vpk` or `--to-keys`). #[arg(long)] to_identifier: Option, /// amount - amount of balance to move. @@ -80,7 +84,7 @@ impl WalletSubcommand for AuthTransferSubcommand { let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; - if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { + if let LeeTransaction::PrivacyPreserving(tx) = transfer_tx { let acc_decode_data = vec![Decode(secret, account_id)]; wallet_core.decode_insert_privacy_preserving_transaction_results( @@ -100,9 +104,18 @@ impl WalletSubcommand for AuthTransferSubcommand { to: to_account, to_npk, to_vpk, + to_keys, to_identifier, amount, } => { + // Resolve --to-keys into --to-npk / --to-vpk equivalents. + let (to_npk, to_vpk) = if let Some(path) = to_keys { + let (npk_bytes, vpk_bytes) = crate::cli::read_keys_file(&path)?; + (Some(hex::encode(npk_bytes)), Some(hex::encode(vpk_bytes))) + } else { + (to_npk, to_vpk) + }; + let from = from_account.resolve(wallet_core.storage())?; let to = to_account .as_ref() @@ -250,7 +263,7 @@ pub enum NativeTokenTransferProgramSubcommandShielded { /// `to_npk` - valid 32 byte hex string. #[arg(long)] to_npk: String, - /// `to_vpk` - valid 33 byte hex string. + /// `to_vpk` - valid hex-encoded ML-KEM-768 encapsulation key (1184 bytes). #[arg(long)] to_vpk: String, /// Identifier for the recipient's private account. @@ -290,7 +303,7 @@ pub enum NativeTokenTransferProgramSubcommandPrivate { /// `to_npk` - valid 32 byte hex string. #[arg(long)] to_npk: String, - /// `to_vpk` - valid 33 byte hex string. + /// `to_vpk` - valid hex-encoded ML-KEM-768 encapsulation key (1184 bytes). #[arg(long)] to_vpk: String, /// Identifier for the recipient's private account. @@ -317,7 +330,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate { let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; - if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { + if let LeeTransaction::PrivacyPreserving(tx) = transfer_tx { let acc_decode_data = vec![Decode(secret_from, from), Decode(secret_to, to)]; wallet_core.decode_insert_privacy_preserving_transaction_results( @@ -340,13 +353,12 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate { let to_npk_res = hex::decode(to_npk)?; let mut to_npk = [0; 32]; to_npk.copy_from_slice(&to_npk_res); - let to_npk = nssa_core::NullifierPublicKey(to_npk); + let to_npk = lee_core::NullifierPublicKey(to_npk); - let to_vpk_res = hex::decode(to_vpk)?; - let mut to_vpk = [0_u8; 33]; - to_vpk.copy_from_slice(&to_vpk_res); - let to_vpk = - nssa_core::encryption::shared_key_derivation::Secp256k1Point(to_vpk.to_vec()); + let to_vpk_res = hex::decode(&to_vpk) + .context("wallet::cli::programs::native_token_transfer: to_vpk must be a valid hex string")?; + let to_vpk = lee_core::encryption::ViewingPublicKey::from_bytes(to_vpk_res) + .map_err(|e| anyhow::anyhow!("{e}"))?; let (tx_hash, [secret_from, _]) = NativeTokenTransfer(wallet_core) .send_private_transfer_to_outer_account( @@ -362,7 +374,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate { let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; - if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { + if let LeeTransaction::PrivacyPreserving(tx) = transfer_tx { let acc_decode_data = vec![Decode(secret_from, from)]; wallet_core.decode_insert_privacy_preserving_transaction_results( @@ -398,7 +410,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded { let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; - if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { + if let LeeTransaction::PrivacyPreserving(tx) = transfer_tx { let acc_decode_data = vec![Decode(secret, to)]; wallet_core.decode_insert_privacy_preserving_transaction_results( @@ -421,13 +433,12 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded { let to_npk_res = hex::decode(to_npk)?; let mut to_npk = [0; 32]; to_npk.copy_from_slice(&to_npk_res); - let to_npk = nssa_core::NullifierPublicKey(to_npk); + let to_npk = lee_core::NullifierPublicKey(to_npk); - let to_vpk_res = hex::decode(to_vpk)?; - let mut to_vpk = [0_u8; 33]; - to_vpk.copy_from_slice(&to_vpk_res); - let to_vpk = - nssa_core::encryption::shared_key_derivation::Secp256k1Point(to_vpk.to_vec()); + let to_vpk_res = hex::decode(&to_vpk) + .context("wallet::cli::programs::native_token_transfer: to_vpk must be a valid hex string")?; + let to_vpk = lee_core::encryption::ViewingPublicKey::from_bytes(to_vpk_res) + .map_err(|e| anyhow::anyhow!("{e}"))?; let (tx_hash, _) = NativeTokenTransfer(wallet_core) .send_shielded_transfer_to_outer_account( @@ -470,7 +481,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommand { let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; - if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { + if let LeeTransaction::PrivacyPreserving(tx) = transfer_tx { let acc_decode_data = vec![Decode(secret, from)]; wallet_core.decode_insert_privacy_preserving_transaction_results( diff --git a/wallet/src/cli/programs/pinata.rs b/lez/wallet/src/cli/programs/pinata.rs similarity index 98% rename from wallet/src/cli/programs/pinata.rs rename to lez/wallet/src/cli/programs/pinata.rs index ecde5d58..7ef92270 100644 --- a/wallet/src/cli/programs/pinata.rs +++ b/lez/wallet/src/cli/programs/pinata.rs @@ -1,7 +1,7 @@ use anyhow::{Context as _, Result}; use clap::Subcommand; -use common::{PINATA_BASE58, transaction::NSSATransaction}; -use nssa::{Account, AccountId}; +use common::{PINATA_BASE58, transaction::LeeTransaction}; +use lee::{Account, AccountId}; use crate::{ AccDecodeData::Decode, @@ -150,7 +150,7 @@ impl WalletSubcommand for PinataProgramSubcommandPrivate { println!("Transaction data is {transfer_tx:?}"); - if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { + if let LeeTransaction::PrivacyPreserving(tx) = transfer_tx { let acc_decode_data = vec![Decode(secret_winner, winner_account_id)]; wallet_core.decode_insert_privacy_preserving_transaction_results( diff --git a/wallet/src/cli/programs/token.rs b/lez/wallet/src/cli/programs/token.rs similarity index 91% rename from wallet/src/cli/programs/token.rs rename to lez/wallet/src/cli/programs/token.rs index 12abc309..4ef5dfee 100644 --- a/wallet/src/cli/programs/token.rs +++ b/lez/wallet/src/cli/programs/token.rs @@ -1,7 +1,7 @@ -use anyhow::Result; +use anyhow::{Context as _, Result}; use clap::Subcommand; -use common::transaction::NSSATransaction; -use nssa::AccountId; +use common::transaction::LeeTransaction; +use lee::AccountId; use crate::{ AccDecodeData::Decode, @@ -41,13 +41,17 @@ pub enum TokenProgramAgnosticSubcommand { #[arg(long)] to: Option, /// `to_npk` - valid 32 byte hex string. - #[arg(long)] + #[arg(long, conflicts_with = "to_keys")] to_npk: Option, - /// `to_vpk` - valid 33 byte hex string. - #[arg(long)] + /// `to_vpk` - valid hex-encoded ML-KEM-768 encapsulation key (1184 bytes). + #[arg(long, conflicts_with = "to_keys")] to_vpk: Option, + /// Path to a keys file exported by `wallet account show-keys`, containing npk + /// and vpk on separate lines. Replaces `--to-npk` and `--to-vpk`. + #[arg(long, conflicts_with_all = ["to_npk", "to_vpk"])] + to_keys: Option, /// Identifier for the recipient's private account (only used when sending to a foreign - /// private account via `--to-npk`/`--to-vpk`). + /// private account via `--to-npk`/`--to-vpk` or `--to-keys`). #[arg(long)] to_identifier: Option, /// amount - amount of balance to move. @@ -87,13 +91,17 @@ pub enum TokenProgramAgnosticSubcommand { #[arg(long)] holder: Option, /// `holder_npk` - valid 32 byte hex string. - #[arg(long)] + #[arg(long, conflicts_with = "holder_keys")] holder_npk: Option, - /// `to_vpk` - valid 33 byte hex string. - #[arg(long)] + /// `holder_vpk` - valid hex-encoded ML-KEM-768 encapsulation key (1184 bytes). + #[arg(long, conflicts_with = "holder_keys")] holder_vpk: Option, + /// Path to a keys file exported by `wallet account show-keys`, containing npk + /// and vpk on separate lines. Replaces `--holder-npk` and `--holder-vpk`. + #[arg(long, conflicts_with_all = ["holder_npk", "holder_vpk"])] + holder_keys: Option, /// Identifier for the holder's private account (only used when minting to a foreign - /// private account via `--holder-npk`/`--holder-vpk`). + /// private account via `--holder-npk`/`--holder-vpk` or `--holder-keys`). #[arg(long)] holder_identifier: Option, /// amount - amount of balance to mint. @@ -171,11 +179,20 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand { to, to_npk, to_vpk, + to_keys, to_identifier, amount, } => { let from_mention = from.clone(); let to_mention = to.clone(); + let (to_npk, to_vpk) = if let Some(path) = to_keys { + let (npk_bytes, vpk_bytes) = crate::cli::read_keys_file(&path)?; + (Some(hex::encode(npk_bytes)), Some(hex::encode(vpk_bytes))) + } else { + (to_npk, to_vpk) + }; + + let from = from.resolve(wallet_core.storage())?; let to = to .map(|account_mention| account_mention.resolve(wallet_core.storage())) @@ -312,11 +329,20 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand { holder, holder_npk, holder_vpk, + holder_keys, holder_identifier, amount, } => { let def_mention = definition.clone(); let holder_mention = holder.clone(); + let (holder_npk, holder_vpk) = if let Some(path) = holder_keys { + let (npk_bytes, vpk_bytes) = crate::cli::read_keys_file(&path)?; + (Some(hex::encode(npk_bytes)), Some(hex::encode(vpk_bytes))) + } else { + (holder_npk, holder_vpk) + }; + + let definition = definition.resolve(wallet_core.storage())?; let holder = holder .map(|account_mention| account_mention.resolve(wallet_core.storage())) @@ -479,7 +505,7 @@ pub enum TokenProgramSubcommandPrivate { /// `recipient_npk` - valid 32 byte hex string. #[arg(long)] recipient_npk: String, - /// `recipient_vpk` - valid 33 byte hex string. + /// `recipient_vpk` - valid hex-encoded ML-KEM-768 encapsulation key (1184 bytes). #[arg(long)] recipient_vpk: String, /// Identifier for the recipient's private account. @@ -573,7 +599,7 @@ pub enum TokenProgramSubcommandShielded { /// `recipient_npk` - valid 32 byte hex string. #[arg(long)] recipient_npk: String, - /// `recipient_vpk` - valid 33 byte hex string. + /// `recipient_vpk` - valid hex-encoded ML-KEM-768 encapsulation key (1184 bytes). #[arg(long)] recipient_vpk: String, /// Identifier for the recipient's private account. @@ -786,7 +812,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; - if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { + if let LeeTransaction::PrivacyPreserving(tx) = transfer_tx { let acc_decode_data = vec![ Decode(secret_sender, sender_account_id), Decode(secret_recipient, recipient_account_id), @@ -812,14 +838,14 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { let recipient_npk_res = hex::decode(recipient_npk)?; let mut recipient_npk = [0; 32]; recipient_npk.copy_from_slice(&recipient_npk_res); - let recipient_npk = nssa_core::NullifierPublicKey(recipient_npk); + let recipient_npk = lee_core::NullifierPublicKey(recipient_npk); - let recipient_vpk_res = hex::decode(recipient_vpk)?; - let mut recipient_vpk = [0_u8; 33]; - recipient_vpk.copy_from_slice(&recipient_vpk_res); - let recipient_vpk = nssa_core::encryption::shared_key_derivation::Secp256k1Point( - recipient_vpk.to_vec(), - ); + let recipient_vpk_res = hex::decode(&recipient_vpk).context( + "wallet::cli::programs::token: recipient_vpk must be a valid hex string", + )?; + let recipient_vpk = + lee_core::encryption::ViewingPublicKey::from_bytes(recipient_vpk_res) + .map_err(|e| anyhow::anyhow!("{e}"))?; let (tx_hash, [secret_sender, _]) = Token(wallet_core) .send_transfer_transaction_private_foreign_account( @@ -835,7 +861,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; - if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { + if let LeeTransaction::PrivacyPreserving(tx) = transfer_tx { let acc_decode_data = vec![Decode(secret_sender, sender_account_id)]; wallet_core.decode_insert_privacy_preserving_transaction_results( @@ -865,7 +891,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; - if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { + if let LeeTransaction::PrivacyPreserving(tx) = transfer_tx { let acc_decode_data = vec![ Decode(secret_definition, definition_account_id), Decode(secret_holder, holder_account_id), @@ -898,7 +924,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; - if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { + if let LeeTransaction::PrivacyPreserving(tx) = transfer_tx { let acc_decode_data = vec![ Decode(secret_definition, definition_account_id), Decode(secret_holder, holder_account_id), @@ -924,14 +950,13 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { let holder_npk_res = hex::decode(holder_npk)?; let mut holder_npk = [0; 32]; holder_npk.copy_from_slice(&holder_npk_res); - let holder_npk = nssa_core::NullifierPublicKey(holder_npk); + let holder_npk = lee_core::NullifierPublicKey(holder_npk); - let holder_vpk_res = hex::decode(holder_vpk)?; - let mut holder_vpk = [0_u8; 33]; - holder_vpk.copy_from_slice(&holder_vpk_res); - let holder_vpk = nssa_core::encryption::shared_key_derivation::Secp256k1Point( - holder_vpk.to_vec(), - ); + let holder_vpk_res = hex::decode(&holder_vpk).context( + "wallet::cli::programs::token: holder_vpk must be a valid hex string", + )?; + let holder_vpk = lee_core::encryption::ViewingPublicKey::from_bytes(holder_vpk_res) + .map_err(|e| anyhow::anyhow!("{e}"))?; let (tx_hash, [secret_definition, _]) = Token(wallet_core) .send_mint_transaction_private_foreign_account( @@ -947,7 +972,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; - if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { + if let LeeTransaction::PrivacyPreserving(tx) = transfer_tx { let acc_decode_data = vec![Decode(secret_definition, definition_account_id)]; wallet_core.decode_insert_privacy_preserving_transaction_results( @@ -987,7 +1012,7 @@ impl WalletSubcommand for TokenProgramSubcommandDeshielded { let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; - if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { + if let LeeTransaction::PrivacyPreserving(tx) = transfer_tx { let acc_decode_data = vec![Decode(secret_sender, sender_account_id)]; wallet_core.decode_insert_privacy_preserving_transaction_results( @@ -1017,7 +1042,7 @@ impl WalletSubcommand for TokenProgramSubcommandDeshielded { let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; - if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { + if let LeeTransaction::PrivacyPreserving(tx) = transfer_tx { let acc_decode_data = vec![Decode(secret_definition, definition_account_id)]; wallet_core.decode_insert_privacy_preserving_transaction_results( @@ -1047,7 +1072,7 @@ impl WalletSubcommand for TokenProgramSubcommandDeshielded { let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; - if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { + if let LeeTransaction::PrivacyPreserving(tx) = transfer_tx { let acc_decode_data = vec![Decode(secret_definition, definition_account_id)]; wallet_core.decode_insert_privacy_preserving_transaction_results( @@ -1080,14 +1105,14 @@ impl WalletSubcommand for TokenProgramSubcommandShielded { let recipient_npk_res = hex::decode(recipient_npk)?; let mut recipient_npk = [0; 32]; recipient_npk.copy_from_slice(&recipient_npk_res); - let recipient_npk = nssa_core::NullifierPublicKey(recipient_npk); + let recipient_npk = lee_core::NullifierPublicKey(recipient_npk); - let recipient_vpk_res = hex::decode(recipient_vpk)?; - let mut recipient_vpk = [0_u8; 33]; - recipient_vpk.copy_from_slice(&recipient_vpk_res); - let recipient_vpk = nssa_core::encryption::shared_key_derivation::Secp256k1Point( - recipient_vpk.to_vec(), - ); + let recipient_vpk_res = hex::decode(&recipient_vpk).context( + "wallet::cli::programs::token: recipient_vpk must be a valid hex string", + )?; + let recipient_vpk = + lee_core::encryption::ViewingPublicKey::from_bytes(recipient_vpk_res) + .map_err(|e| anyhow::anyhow!("{e}"))?; let (tx_hash, _) = Token(wallet_core) .send_transfer_transaction_shielded_foreign_account( @@ -1103,7 +1128,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded { let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; - if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { + if let LeeTransaction::PrivacyPreserving(tx) = transfer_tx { println!("Transaction data is {:?}", tx.message); } @@ -1128,7 +1153,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded { let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; - if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { + if let LeeTransaction::PrivacyPreserving(tx) = transfer_tx { let acc_decode_data = vec![Decode(secret_recipient, recipient_account_id)]; wallet_core.decode_insert_privacy_preserving_transaction_results( @@ -1158,7 +1183,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded { let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; - if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { + if let LeeTransaction::PrivacyPreserving(tx) = transfer_tx { let acc_decode_data = vec![Decode(secret_holder, holder_account_id)]; wallet_core.decode_insert_privacy_preserving_transaction_results( @@ -1188,7 +1213,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded { let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; - if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { + if let LeeTransaction::PrivacyPreserving(tx) = transfer_tx { let acc_decode_data = vec![Decode(secret_holder, holder_account_id)]; wallet_core.decode_insert_privacy_preserving_transaction_results( @@ -1211,14 +1236,13 @@ impl WalletSubcommand for TokenProgramSubcommandShielded { let holder_npk_res = hex::decode(holder_npk)?; let mut holder_npk = [0; 32]; holder_npk.copy_from_slice(&holder_npk_res); - let holder_npk = nssa_core::NullifierPublicKey(holder_npk); + let holder_npk = lee_core::NullifierPublicKey(holder_npk); - let holder_vpk_res = hex::decode(holder_vpk)?; - let mut holder_vpk = [0_u8; 33]; - holder_vpk.copy_from_slice(&holder_vpk_res); - let holder_vpk = nssa_core::encryption::shared_key_derivation::Secp256k1Point( - holder_vpk.to_vec(), - ); + let holder_vpk_res = hex::decode(&holder_vpk).context( + "wallet::cli::programs::token: holder_vpk must be a valid hex string", + )?; + let holder_vpk = lee_core::encryption::ViewingPublicKey::from_bytes(holder_vpk_res) + .map_err(|e| anyhow::anyhow!("{e}"))?; let (tx_hash, _) = Token(wallet_core) .send_mint_transaction_shielded_foreign_account( @@ -1234,7 +1258,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded { let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; - if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { + if let LeeTransaction::PrivacyPreserving(tx) = transfer_tx { println!("Transaction data is {:?}", tx.message); } @@ -1271,7 +1295,7 @@ impl WalletSubcommand for CreateNewTokenProgramSubcommand { let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; - if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { + if let LeeTransaction::PrivacyPreserving(tx) = transfer_tx { let acc_decode_data = vec![ Decode(secret_definition, definition_account_id), Decode(secret_supply, supply_account_id), @@ -1306,7 +1330,7 @@ impl WalletSubcommand for CreateNewTokenProgramSubcommand { let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; - if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { + if let LeeTransaction::PrivacyPreserving(tx) = transfer_tx { let acc_decode_data = vec![Decode(secret_definition, definition_account_id)]; wallet_core.decode_insert_privacy_preserving_transaction_results( @@ -1338,7 +1362,7 @@ impl WalletSubcommand for CreateNewTokenProgramSubcommand { let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?; - if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { + if let LeeTransaction::PrivacyPreserving(tx) = transfer_tx { let acc_decode_data = vec![Decode(secret_supply, supply_account_id)]; wallet_core.decode_insert_privacy_preserving_transaction_results( diff --git a/wallet/src/config.rs b/lez/wallet/src/config.rs similarity index 100% rename from wallet/src/config.rs rename to lez/wallet/src/config.rs diff --git a/wallet/src/helperfunctions.rs b/lez/wallet/src/helperfunctions.rs similarity index 88% rename from wallet/src/helperfunctions.rs rename to lez/wallet/src/helperfunctions.rs index 39a6b168..6fe78681 100644 --- a/wallet/src/helperfunctions.rs +++ b/lez/wallet/src/helperfunctions.rs @@ -1,7 +1,7 @@ use std::{path::PathBuf, str::FromStr as _}; use anyhow::{Context as _, Result}; -use nssa_core::account::Nonce; +use lee_core::account::Nonce; use rand::{RngCore as _, rngs::OsRng}; use crate::HOME_DIR_ENV_VAR; @@ -33,21 +33,21 @@ pub fn read_mnemonic() -> anyhow::Result> { .map_err(Into::into) } -/// Get home dir for wallet. Env var `NSSA_WALLET_HOME_DIR` must be set before execution to succeed. -fn get_home_nssa_var() -> Result { +/// Get home dir for wallet. Env var `LEE_WALLET_HOME_DIR` must be set before execution to succeed. +fn get_home_lee_var() -> Result { Ok(PathBuf::from_str(&std::env::var(HOME_DIR_ENV_VAR)?)?) } /// Get home dir for wallet. Env var `HOME` must be set before execution to succeed. fn get_home_default_path() -> Result { std::env::home_dir() - .map(|path| path.join(".nssa").join("wallet")) + .map(|path| path.join(".lee").join("wallet")) .context("Failed to get HOME") } /// Get home dir for wallet. pub fn get_home() -> Result { - get_home_nssa_var().or_else(|_| get_home_default_path()) + get_home_lee_var().or_else(|_| get_home_default_path()) } /// Fetch config path from default home. diff --git a/wallet/src/lib.rs b/lez/wallet/src/lib.rs similarity index 91% rename from wallet/src/lib.rs rename to lez/wallet/src/lib.rs index 6c89f3dc..0afcda6d 100644 --- a/wallet/src/lib.rs +++ b/lez/wallet/src/lib.rs @@ -13,19 +13,19 @@ use std::path::PathBuf; pub use account_manager::AccountIdentity; use anyhow::{Context as _, Result}; use bip39::Mnemonic; -use common::{HashType, transaction::NSSATransaction}; +use common::{HashType, transaction::LeeTransaction}; use config::WalletConfig; use key_protocol::key_management::key_tree::chain_index::ChainIndex; -use log::info; -use nssa::{ +use lee::{ Account, AccountId, PrivacyPreservingTransaction, privacy_preserving_transaction::{ circuit::ProgramWithDependencies, message::EncryptedAccountData, }, }; -use nssa_core::{ +use lee_core::{ Commitment, MembershipProof, SharedSecretKey, account::Nonce, program::InstructionData, }; +use log::info; use sequencer_service_rpc::{RpcClient as _, SequencerClient, SequencerClientBuilder}; use storage::Storage; use tokio::io::AsyncWriteExt as _; @@ -47,18 +47,18 @@ pub mod program_facades; pub mod signing; pub mod storage; -pub const HOME_DIR_ENV_VAR: &str = "NSSA_WALLET_HOME_DIR"; +pub const HOME_DIR_ENV_VAR: &str = "LEE_WALLET_HOME_DIR"; pub enum AccDecodeData { Skip, - Decode(nssa_core::SharedSecretKey, AccountId), + Decode(lee_core::SharedSecretKey, AccountId), } /// Info returned when creating a shared account. pub struct SharedAccountInfo { pub account_id: AccountId, - pub npk: nssa_core::NullifierPublicKey, - pub vpk: nssa_core::encryption::ViewingPublicKey, + pub npk: lee_core::NullifierPublicKey, + pub vpk: lee_core::encryption::ViewingPublicKey, } #[derive(Debug, thiserror::Error)] @@ -76,7 +76,7 @@ pub enum ExecutionFailureKind { #[error("Account {0} data is invalid")] AccountDataError(AccountId), #[error("Failed to build transaction: {0}")] - TransactionBuildError(#[from] nssa::error::NssaError), + TransactionBuildError(#[from] lee::error::LeeError), #[error("Failed to sign transaction: {0}")] SignError(anyhow::Error), #[error(transparent)] @@ -272,14 +272,17 @@ impl WalletCore { } /// Set the wallet's dedicated sealing secret key. - pub const fn set_sealing_secret_key(&mut self, key: nssa_core::encryption::Scalar) { + pub const fn set_sealing_secret_key( + &mut self, + key: key_protocol::key_management::secret_holders::ViewingSecretKey, + ) { self.storage.key_chain_mut().set_sealing_secret_key(key); } /// Resolve an `AccountId` to the appropriate `AccountIdentity` variant. /// Checks the key tree first, then shared private accounts. #[must_use] - pub fn resolve_private_account(&self, account_id: nssa::AccountId) -> Option { + pub fn resolve_private_account(&self, account_id: lee::AccountId) -> Option { // Check key tree first if self .storage @@ -341,9 +344,9 @@ impl WalletCore { &mut self, account_id: AccountId, group_label: Label, - identifier: nssa_core::Identifier, - pda_seed: Option, - authority_program_id: Option, + identifier: lee_core::Identifier, + pda_seed: Option, + authority_program_id: Option, ) { self.storage.key_chain_mut().insert_shared_private_account( account_id, @@ -361,9 +364,9 @@ impl WalletCore { pub fn create_shared_pda_account( &mut self, group_name: Label, - pda_seed: nssa_core::program::PdaSeed, - program_id: nssa_core::program::ProgramId, - identifier: nssa_core::Identifier, + pda_seed: lee_core::program::PdaSeed, + program_id: lee_core::program::ProgramId, + identifier: lee_core::Identifier, ) -> Result { let holder = self .storage @@ -397,7 +400,7 @@ impl WalletCore { &mut self, group_name: Label, ) -> Result { - let identifier: nssa_core::Identifier = rand::random(); + let identifier: lee_core::Identifier = rand::random(); let derivation_seed = { use sha2::Digest as _; let mut hasher = sha2::Sha256::new(); @@ -459,7 +462,7 @@ impl WalletCore { pub fn get_account_public_signing_key( &self, account_id: AccountId, - ) -> Option<&nssa::PrivateKey> { + ) -> Option<&lee::PrivateKey> { self.storage.key_chain().pub_account_signing_key(account_id) } @@ -488,7 +491,7 @@ impl WalletCore { } /// Poll transactions. - pub async fn poll_native_token_transfer(&self, hash: HashType) -> Result { + pub async fn poll_native_token_transfer(&self, hash: HashType) -> Result { self.poller.poll_tx(hash).await } @@ -508,7 +511,7 @@ impl WalletCore { pub fn decode_insert_privacy_preserving_transaction_results( &mut self, - tx: &nssa::privacy_preserving_transaction::PrivacyPreservingTransaction, + tx: &lee::privacy_preserving_transaction::PrivacyPreservingTransaction, acc_decode_mask: &[AccDecodeData], ) -> Result<()> { for (output_index, acc_decode_data) in acc_decode_mask.iter().enumerate() { @@ -517,7 +520,7 @@ impl WalletCore { let acc_ead = tx.message.encrypted_private_post_states[output_index].clone(); let acc_comm = tx.message.new_commitments[output_index].clone(); - let (kind, res_acc) = nssa_core::EncryptionScheme::decrypt( + let (kind, res_acc) = lee_core::EncryptionScheme::decrypt( &acc_ead.ciphertext, secret, &acc_comm, @@ -573,7 +576,7 @@ impl WalletCore { )?; let private_account_keys = acc_manager.private_account_keys(); - let (output, proof) = nssa::privacy_preserving_transaction::circuit::execute_and_prove( + let (output, proof) = lee::privacy_preserving_transaction::circuit::execute_and_prove( pre_states, instruction_data, acc_manager.account_identities(), @@ -581,7 +584,7 @@ impl WalletCore { )?; let message = - nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output( + lee::privacy_preserving_transaction::message::Message::try_from_circuit_output( acc_manager.public_account_ids(), acc_manager.public_account_nonces(), private_account_keys @@ -597,7 +600,7 @@ impl WalletCore { .map_err(ExecutionFailureKind::SignError)?; let witness_set = - nssa::privacy_preserving_transaction::witness_set::WitnessSet::from_raw_parts( + lee::privacy_preserving_transaction::witness_set::WitnessSet::from_raw_parts( signatures_public_keys, proof, ); @@ -611,7 +614,7 @@ impl WalletCore { Ok(( self.sequencer_client - .send_transaction(NSSATransaction::PrivacyPreserving(tx)) + .send_transaction(LeeTransaction::PrivacyPreserving(tx)) .await?, shared_secrets, )) @@ -637,7 +640,7 @@ impl WalletCore { // Public transaction, all accounts must be public if accounts.iter().any(AccountIdentity::is_private) { return Err(ExecutionFailureKind::TransactionBuildError( - nssa::error::NssaError::InvalidInput( + lee::error::LeeError::InvalidInput( "Private accounts are not allowed in public transactions".to_owned(), ), )); @@ -657,7 +660,7 @@ impl WalletCore { let program_id = program.program.id(); let nonces = acc_manager.public_account_nonces(); - let message = nssa::public_transaction::Message::new_preserialized( + let message = lee::public_transaction::Message::new_preserialized( program_id, account_ids, nonces, @@ -670,13 +673,13 @@ impl WalletCore { .map_err(ExecutionFailureKind::SignError)?; let witness_set = - nssa::public_transaction::WitnessSet::from_raw_parts(signatures_public_keys); + lee::public_transaction::WitnessSet::from_raw_parts(signatures_public_keys); - let tx = nssa::public_transaction::PublicTransaction::new(message, witness_set); + let tx = lee::public_transaction::PublicTransaction::new(message, witness_set); Ok(self .sequencer_client - .send_transaction(NSSATransaction::Public(tx)) + .send_transaction(LeeTransaction::Public(tx)) .await?) } @@ -727,8 +730,8 @@ impl WalletCore { Ok(()) } - fn sync_private_accounts_with_tx(&mut self, tx: NSSATransaction) { - let NSSATransaction::PrivacyPreserving(tx) = tx else { + fn sync_private_accounts_with_tx(&mut self, tx: LeeTransaction) { + let LeeTransaction::PrivacyPreserving(tx) = tx else { return; }; @@ -736,7 +739,7 @@ impl WalletCore { .storage .key_chain() .private_account_key_chains() - .flat_map(|(_account_id, key_chain, index)| { + .flat_map(|(_account_id, key_chain, _index)| { let view_tag = EncryptedAccountData::compute_view_tag( &key_chain.nullifier_public_key, &key_chain.viewing_public_key, @@ -751,12 +754,10 @@ impl WalletCore { .filter_map(move |(ciph_id, encrypted_data)| { let ciphertext = &encrypted_data.ciphertext; let commitment = &new_commitments[ciph_id]; - let shared_secret = key_chain.calculate_shared_secret_receiver( - &encrypted_data.epk, - index.and_then(ChainIndex::index), - ); + let shared_secret = + key_chain.calculate_shared_secret_receiver(&encrypted_data.epk)?; - nssa_core::EncryptionScheme::decrypt( + lee_core::EncryptionScheme::decrypt( ciphertext, &shared_secret, commitment, @@ -766,7 +767,7 @@ impl WalletCore { ) .map(|(kind, res_acc)| { let npk = &key_chain.nullifier_public_key; - let account_id = nssa::AccountId::for_private_account(npk, &kind); + let account_id = lee::AccountId::for_private_account(npk, &kind); (account_id, kind, res_acc) }) }) @@ -836,10 +837,14 @@ impl WalletCore { continue; } - let shared_secret = SharedSecretKey::new(vsk, &encrypted_data.epk); + let Some(shared_secret) = + SharedSecretKey::decapsulate(&encrypted_data.epk, &vsk.d, &vsk.z) + else { + continue; + }; let commitment = &tx.message.new_commitments[ciph_id]; - if let Some((_kind, new_acc)) = nssa_core::EncryptionScheme::decrypt( + if let Some((_kind, new_acc)) = lee_core::EncryptionScheme::decrypt( &encrypted_data.ciphertext, &shared_secret, commitment, diff --git a/wallet/src/main.rs b/lez/wallet/src/main.rs similarity index 100% rename from wallet/src/main.rs rename to lez/wallet/src/main.rs diff --git a/wallet/src/poller.rs b/lez/wallet/src/poller.rs similarity index 94% rename from wallet/src/poller.rs rename to lez/wallet/src/poller.rs index 7dbd59c1..52802887 100644 --- a/wallet/src/poller.rs +++ b/lez/wallet/src/poller.rs @@ -1,7 +1,7 @@ use std::time::Duration; use anyhow::Result; -use common::{HashType, block::Block, transaction::NSSATransaction}; +use common::{HashType, block::Block, transaction::LeeTransaction}; use log::{info, warn}; use sequencer_service_rpc::{RpcClient as _, SequencerClient}; @@ -30,7 +30,7 @@ impl TxPoller { } // TODO: this polling is not based on blocks, but on timeouts, need to fix this. - pub async fn poll_tx(&self, tx_hash: HashType) -> Result { + pub async fn poll_tx(&self, tx_hash: HashType) -> Result { let max_blocks_to_query = self.polling_max_blocks_to_query; info!("Starting poll for transaction {tx_hash}"); diff --git a/wallet/src/program_facades/amm.rs b/lez/wallet/src/program_facades/amm.rs similarity index 99% rename from wallet/src/program_facades/amm.rs rename to lez/wallet/src/program_facades/amm.rs index 1676ee18..e1261b26 100644 --- a/wallet/src/program_facades/amm.rs +++ b/lez/wallet/src/program_facades/amm.rs @@ -1,6 +1,6 @@ use amm_core::{compute_liquidity_token_pda, compute_pool_pda, compute_vault_pda}; use common::HashType; -use nssa::{AccountId, program::Program}; +use lee::{AccountId, program::Program}; use token_core::TokenHolding; use crate::{AccountIdentity, ExecutionFailureKind, WalletCore}; diff --git a/wallet/src/program_facades/ata.rs b/lez/wallet/src/program_facades/ata.rs similarity index 99% rename from wallet/src/program_facades/ata.rs rename to lez/wallet/src/program_facades/ata.rs index 6aba469c..e6b8fc29 100644 --- a/wallet/src/program_facades/ata.rs +++ b/lez/wallet/src/program_facades/ata.rs @@ -2,10 +2,10 @@ use std::collections::HashMap; use ata_core::{compute_ata_seed, get_associated_token_account_id}; use common::HashType; -use nssa::{ +use lee::{ AccountId, privacy_preserving_transaction::circuit::ProgramWithDependencies, program::Program, }; -use nssa_core::SharedSecretKey; +use lee_core::SharedSecretKey; use crate::{AccountIdentity, ExecutionFailureKind, WalletCore}; diff --git a/wallet/src/program_facades/mod.rs b/lez/wallet/src/program_facades/mod.rs similarity index 100% rename from wallet/src/program_facades/mod.rs rename to lez/wallet/src/program_facades/mod.rs diff --git a/wallet/src/program_facades/native_token_transfer/deshielded.rs b/lez/wallet/src/program_facades/native_token_transfer/deshielded.rs similarity index 91% rename from wallet/src/program_facades/native_token_transfer/deshielded.rs rename to lez/wallet/src/program_facades/native_token_transfer/deshielded.rs index 31374f99..f060e0fa 100644 --- a/wallet/src/program_facades/native_token_transfer/deshielded.rs +++ b/lez/wallet/src/program_facades/native_token_transfer/deshielded.rs @@ -1,5 +1,5 @@ use common::HashType; -use nssa::AccountId; +use lee::AccountId; use super::{NativeTokenTransfer, auth_transfer_preparation}; use crate::{AccountIdentity, ExecutionFailureKind}; @@ -10,7 +10,7 @@ impl NativeTokenTransfer<'_> { from: AccountId, to: AccountId, balance_to_move: u128, - ) -> Result<(HashType, nssa_core::SharedSecretKey), ExecutionFailureKind> { + ) -> Result<(HashType, lee_core::SharedSecretKey), ExecutionFailureKind> { let (instruction_data, program, tx_pre_check) = auth_transfer_preparation(balance_to_move); self.0 diff --git a/wallet/src/program_facades/native_token_transfer/mod.rs b/lez/wallet/src/program_facades/native_token_transfer/mod.rs similarity index 93% rename from wallet/src/program_facades/native_token_transfer/mod.rs rename to lez/wallet/src/program_facades/native_token_transfer/mod.rs index 050b90b5..74f9d7b7 100644 --- a/wallet/src/program_facades/native_token_transfer/mod.rs +++ b/lez/wallet/src/program_facades/native_token_transfer/mod.rs @@ -1,5 +1,5 @@ -use nssa::{Account, program::Program}; -use nssa_core::program::InstructionData; +use lee::{Account, program::Program}; +use lee_core::program::InstructionData; use crate::{ExecutionFailureKind, WalletCore}; diff --git a/wallet/src/program_facades/native_token_transfer/private.rs b/lez/wallet/src/program_facades/native_token_transfer/private.rs similarity index 96% rename from wallet/src/program_facades/native_token_transfer/private.rs rename to lez/wallet/src/program_facades/native_token_transfer/private.rs index 481e4a5f..6937ee5a 100644 --- a/wallet/src/program_facades/native_token_transfer/private.rs +++ b/lez/wallet/src/program_facades/native_token_transfer/private.rs @@ -1,8 +1,8 @@ use std::vec; use common::HashType; -use nssa::{AccountId, program::Program}; -use nssa_core::{Identifier, NullifierPublicKey, SharedSecretKey, encryption::ViewingPublicKey}; +use lee::{AccountId, program::Program}; +use lee_core::{Identifier, NullifierPublicKey, SharedSecretKey, encryption::ViewingPublicKey}; use super::{NativeTokenTransfer, auth_transfer_preparation}; use crate::{AccountIdentity, ExecutionFailureKind}; diff --git a/lez/wallet/src/program_facades/native_token_transfer/public.rs b/lez/wallet/src/program_facades/native_token_transfer/public.rs new file mode 100644 index 00000000..f745557a --- /dev/null +++ b/lez/wallet/src/program_facades/native_token_transfer/public.rs @@ -0,0 +1,126 @@ +use authenticated_transfer_core::Instruction as AuthTransferInstruction; +use common::{HashType, transaction::LeeTransaction}; +use lee::{ + AccountId, PublicTransaction, + program::Program, + public_transaction::{Message, WitnessSet}, +}; +use pyo3::exceptions::PyRuntimeError; +use sequencer_service_rpc::RpcClient as _; + +use super::NativeTokenTransfer; +use crate::{ + AccountIdentity, ExecutionFailureKind, + program_facades::native_token_transfer::auth_transfer_preparation, +}; + +impl NativeTokenTransfer<'_> { + pub async fn send_public_transfer( + &self, + from: AccountIdentity, + to: AccountIdentity, + balance_to_move: u128, + ) -> Result { + let (instruction_data, program, tx_pre_check) = auth_transfer_preparation(balance_to_move); + + self.0 + .send_pub_tx_with_pre_check( + vec![from, to], + instruction_data, + &program.into(), + tx_pre_check, + ) + .await + .map_err(ExecutionFailureKind::SequencerError)?; + + let message = Message::try_new( + program_id, + vec![from, to], + nonces, + AuthTransferInstruction::Transfer { + amount: balance_to_move, + }, + ) + .map_err(ExecutionFailureKind::TransactionBuildError)?; + + let pin = if groups.needs_pin() { + read_pin() + .map_err(|e| { + ExecutionFailureKind::KeycardError(pyo3::PyErr::new::( + e.to_string(), + )) + })? + .as_str() + .to_owned() + } else { + String::new() + }; + + let sigs = groups.sign_all(&message.hash(), &pin).map_err(|e| { + ExecutionFailureKind::KeycardError(pyo3::PyErr::new::(e.to_string())) + })?; + + let tx = PublicTransaction::new(message, WitnessSet::from_raw_parts(sigs)); + Ok(self + .0 + .sequencer_client + .send_transaction(LeeTransaction::Public(tx)) + .await?) + } + + pub async fn register_account( + &self, + account: AccountIdentity, + ) -> Result { + let program = Program::authenticated_transfer_program(); + let instruction_data = Program::serialize_instruction(AuthTransferInstruction::Initialize)?; + + self.0 + .send_pub_tx(vec![account], instruction_data, &program.into()) + .await + .map_err(ExecutionFailureKind::SequencerError)?; + + let account_ids = vec![from]; + let program_id = Program::authenticated_transfer_program().id(); + let message = Message::try_new( + program_id, + account_ids, + nonces, + AuthTransferInstruction::Initialize, + ) + .map_err(ExecutionFailureKind::TransactionBuildError)?; + + let mut groups = SigningGroups::new(); + groups + .add_sender(account_mention, from, self.0) + .map_err(|e| { + ExecutionFailureKind::KeycardError(pyo3::PyErr::new::( + e.to_string(), + )) + })?; + + let pin = if groups.needs_pin() { + read_pin() + .map_err(|e| { + ExecutionFailureKind::KeycardError(pyo3::PyErr::new::( + e.to_string(), + )) + })? + .as_str() + .to_owned() + } else { + String::new() + }; + + let sigs = groups.sign_all(&message.hash(), &pin).map_err(|e| { + ExecutionFailureKind::KeycardError(pyo3::PyErr::new::(e.to_string())) + })?; + + let tx = PublicTransaction::new(message, WitnessSet::from_raw_parts(sigs)); + Ok(self + .0 + .sequencer_client + .send_transaction(LeeTransaction::Public(tx)) + .await?) + } +} diff --git a/wallet/src/program_facades/native_token_transfer/shielded.rs b/lez/wallet/src/program_facades/native_token_transfer/shielded.rs similarity index 95% rename from wallet/src/program_facades/native_token_transfer/shielded.rs rename to lez/wallet/src/program_facades/native_token_transfer/shielded.rs index e745346a..002b1176 100644 --- a/wallet/src/program_facades/native_token_transfer/shielded.rs +++ b/lez/wallet/src/program_facades/native_token_transfer/shielded.rs @@ -1,6 +1,6 @@ use common::HashType; -use nssa::AccountId; -use nssa_core::{Identifier, NullifierPublicKey, SharedSecretKey, encryption::ViewingPublicKey}; +use lee::AccountId; +use lee_core::{Identifier, NullifierPublicKey, SharedSecretKey, encryption::ViewingPublicKey}; use super::{NativeTokenTransfer, auth_transfer_preparation}; use crate::{AccountIdentity, ExecutionFailureKind}; diff --git a/wallet/src/program_facades/pinata.rs b/lez/wallet/src/program_facades/pinata.rs similarity index 91% rename from wallet/src/program_facades/pinata.rs rename to lez/wallet/src/program_facades/pinata.rs index 2e40e78b..8da5f1a5 100644 --- a/wallet/src/program_facades/pinata.rs +++ b/lez/wallet/src/program_facades/pinata.rs @@ -1,6 +1,6 @@ use common::HashType; -use nssa::{AccountId, program::Program}; -use nssa_core::{MembershipProof, SharedSecretKey}; +use lee::{AccountId, program::Program}; +use lee_core::{MembershipProof, SharedSecretKey}; use crate::{AccountIdentity, ExecutionFailureKind, WalletCore}; @@ -60,8 +60,8 @@ impl Pinata<'_> { .resolve_private_account(winner_account_id) .ok_or(ExecutionFailureKind::KeyNotFoundError)?, ], - nssa::program::Program::serialize_instruction(solution).unwrap(), - &nssa::program::Program::pinata().into(), + lee::program::Program::serialize_instruction(solution).unwrap(), + &lee::program::Program::pinata().into(), ) .await .map(|(resp, secrets)| { diff --git a/wallet/src/program_facades/token.rs b/lez/wallet/src/program_facades/token.rs similarity index 99% rename from wallet/src/program_facades/token.rs rename to lez/wallet/src/program_facades/token.rs index 4d026a66..2170c046 100644 --- a/wallet/src/program_facades/token.rs +++ b/lez/wallet/src/program_facades/token.rs @@ -1,6 +1,6 @@ use common::HashType; -use nssa::{AccountId, program::Program}; -use nssa_core::{Identifier, NullifierPublicKey, SharedSecretKey, encryption::ViewingPublicKey}; +use lee::{AccountId, program::Program}; +use lee_core::{Identifier, NullifierPublicKey, SharedSecretKey, encryption::ViewingPublicKey}; use token_core::Instruction; use crate::{AccountIdentity, ExecutionFailureKind, WalletCore}; diff --git a/wallet/src/signing.rs b/lez/wallet/src/signing.rs similarity index 94% rename from wallet/src/signing.rs rename to lez/wallet/src/signing.rs index 505dedd9..299a33b7 100644 --- a/wallet/src/signing.rs +++ b/lez/wallet/src/signing.rs @@ -1,4 +1,5 @@ use keycard_wallet::{KeycardWallet, python_path}; +use lee::{AccountId, PrivateKey, PublicKey, Signature}; use pyo3::Python; /// Lazily opens and reuses a single Keycard session for all keycard signers in one transaction. diff --git a/wallet/src/storage.rs b/lez/wallet/src/storage.rs similarity index 95% rename from wallet/src/storage.rs rename to lez/wallet/src/storage.rs index 35d0531f..d1415c2b 100644 --- a/wallet/src/storage.rs +++ b/lez/wallet/src/storage.rs @@ -11,7 +11,7 @@ use key_protocol::key_management::{ key_tree::{KeyTreePrivate, KeyTreePublic}, secret_holders::SeedHolder, }; -use nssa_core::BlockId; +use lee_core::BlockId; use crate::{ account::{AccountIdWithPrivacy, Label}, @@ -205,13 +205,13 @@ mod tests { .key_chain_mut() .generate_new_privacy_preserving_transaction_key_chain(None); - let private_key = nssa::PrivateKey::new_os_random(); + let private_key = lee::PrivateKey::new_os_random(); storage .key_chain_mut() .add_imported_public_account(private_key); let key_chain = key_protocol::key_management::KeyChain::new_os_random(); - let account = nssa::Account::default(); + let account = lee::Account::default(); storage .key_chain_mut() .add_imported_private_account(key_chain, None, 0, account); @@ -232,7 +232,7 @@ mod tests { let (mut storage, _) = Storage::new("test_pass").unwrap(); let label = Label::new("test_label"); - let account_id = AccountIdWithPrivacy::Public(nssa::AccountId::default()); + let account_id = AccountIdWithPrivacy::Public(lee::AccountId::default()); storage.add_label(label.clone(), account_id).unwrap(); assert_eq!(storage.resolve_label(&label), Some(account_id)); @@ -251,7 +251,7 @@ mod tests { let (mut storage, _) = Storage::new("test_pass").unwrap(); let label = Label::new("test_label"); - let account_id = AccountIdWithPrivacy::Public(nssa::AccountId::default()); + let account_id = AccountIdWithPrivacy::Public(lee::AccountId::default()); storage.add_label(label.clone(), account_id).unwrap(); let another_label = Label::new("another_label"); @@ -269,7 +269,7 @@ mod tests { let (mut storage, _) = Storage::new("test_pass").unwrap(); let label = Label::new("test_label"); - let account_id = AccountIdWithPrivacy::Public(nssa::AccountId::default()); + let account_id = AccountIdWithPrivacy::Public(lee::AccountId::default()); assert!(storage.check_label_availability(&label).is_ok()); storage.add_label(label.clone(), account_id).unwrap(); diff --git a/wallet/src/storage/key_chain.rs b/lez/wallet/src/storage/key_chain.rs similarity index 93% rename from wallet/src/storage/key_chain.rs rename to lez/wallet/src/storage/key_chain.rs index 637884f1..f73833eb 100644 --- a/wallet/src/storage/key_chain.rs +++ b/lez/wallet/src/storage/key_chain.rs @@ -6,11 +6,11 @@ use key_protocol::key_management::{ KeyChain, group_key_holder::GroupKeyHolder, key_tree::{KeyTreePrivate, KeyTreePublic, chain_index::ChainIndex, traits::KeyTreeNode as _}, - secret_holders::SeedHolder, + secret_holders::{SeedHolder, ViewingSecretKey}, }; +use lee::{Account, AccountId}; +use lee_core::{Identifier, PrivateAccountKind}; use log::{debug, warn}; -use nssa::{Account, AccountId}; -use nssa_core::{Identifier, PrivateAccountKind}; use serde::{Deserialize, Serialize}; use testnet_initial_state::{PrivateAccountPrivateInitialData, PublicAccountPrivateInitialData}; @@ -54,8 +54,8 @@ pub struct SharedAccountEntry { pub identifier: Identifier, /// For PDA accounts, the seed and program ID used to derive keys via `derive_keys_for_pda`. /// `None` for regular shared accounts (keys derived from identifier via derivation seed). - pub pda_seed: Option, - pub authority_program_id: Option, + pub pda_seed: Option, + pub authority_program_id: Option, pub account: Account, } @@ -63,7 +63,7 @@ pub struct SharedAccountEntry { #[cfg_attr(test, derive(PartialEq, Eq))] pub struct UserKeyChain { /// Imported public accounts. - imported_public_accounts: BTreeMap, + imported_public_accounts: BTreeMap, /// Imported private accounts. imported_private_accounts: BTreeMap, /// Tree of public account keys. @@ -73,13 +73,13 @@ pub struct UserKeyChain { /// Cached plaintext state of shared private accounts (PDAs and regular shared accounts), /// keyed by `AccountId`. Each entry stores the group label and identifier needed /// to re-derive keys during sync. - shared_private_accounts: BTreeMap, + shared_private_accounts: BTreeMap, /// Group key holders for shared account management, keyed by a human-readable label. group_key_holders: BTreeMap, /// Dedicated sealing secret key for GMS distribution. Generated once via /// `wallet group new-sealing-key`. The corresponding public key is shared with /// group members so they can seal GMS for this wallet. - sealing_secret_key: Option, + sealing_secret_key: Option, } impl UserKeyChain { @@ -113,7 +113,7 @@ impl UserKeyChain { /// For more details see /// [`key_protocol::key_management::key_tree::KeyTreePublic::cleanup_tree_remove_uninit_layered()`] /// and [`key_protocol::key_management::key_tree::KeyTreePrivate::cleanup_tree_remove_uninit_layered()`]. - pub async fn cleanup_trees_remove_uninit_layered>>( + pub async fn cleanup_trees_remove_uninit_layered>>( &mut self, depth: u32, get_account: impl Fn(AccountId) -> F, @@ -147,7 +147,7 @@ impl UserKeyChain { /// Returns the signing key for public transaction signatures. #[must_use] - pub fn pub_account_signing_key(&self, account_id: AccountId) -> Option<&nssa::PrivateKey> { + pub fn pub_account_signing_key(&self, account_id: AccountId) -> Option<&lee::PrivateKey> { self.imported_public_accounts .get(&account_id) .or_else(|| self.public_key_tree.get_node(account_id).map(Into::into)) @@ -199,7 +199,7 @@ impl UserKeyChain { &mut self, cci: &ChainIndex, identifier: Identifier, - ) -> Option { + ) -> Option { self.private_key_tree .register_identifier_on_node(cci, identifier) } @@ -281,8 +281,8 @@ impl UserKeyChain { ) } - pub fn add_imported_public_account(&mut self, private_key: nssa::PrivateKey) { - let account_id = AccountId::from(&nssa::PublicKey::new_from_private_key(&private_key)); + pub fn add_imported_public_account(&mut self, private_key: lee::PrivateKey) { + let account_id = AccountId::from(&lee::PublicKey::new_from_private_key(&private_key)); self.imported_public_accounts .insert(account_id, private_key); @@ -328,7 +328,7 @@ impl UserKeyChain { &mut self, account_id: AccountId, kind: PrivateAccountKind, - account: nssa_core::account::Account, + account: lee_core::account::Account, ) -> Result<()> { // Try to find in shared accounts if let Some(entry) = self.shared_private_accounts.get_mut(&account_id) { @@ -379,7 +379,7 @@ impl UserKeyChain { // Node not yet in account_id_map — find it by checking all nodes for (ci, node) in &mut self.private_key_tree.key_map { let expected_id = - nssa::AccountId::for_private_account(&node.value.0.nullifier_public_key, &kind); + lee::AccountId::for_private_account(&node.value.0.nullifier_public_key, &kind); if expected_id == account_id { match node.value.1.entry(kind) { Entry::Occupied(mut occupied) => { @@ -451,7 +451,7 @@ impl UserKeyChain { #[must_use] pub fn shared_private_account( &self, - account_id: nssa::AccountId, + account_id: lee::AccountId, ) -> Option<&SharedAccountEntry> { self.shared_private_accounts.get(&account_id) } @@ -459,7 +459,7 @@ impl UserKeyChain { /// Inserts or replaces a shared private account entry. pub fn insert_shared_private_account( &mut self, - account_id: nssa::AccountId, + account_id: lee::AccountId, entry: SharedAccountEntry, ) { self.shared_private_accounts.insert(account_id, entry); @@ -468,8 +468,8 @@ impl UserKeyChain { /// Updates the cached account state for a shared private account. pub fn update_shared_private_account_state( &mut self, - account_id: &nssa::AccountId, - account: nssa_core::account::Account, + account_id: &lee::AccountId, + account: lee_core::account::Account, ) { if let Some(entry) = self.shared_private_accounts.get_mut(account_id) { entry.account = account; @@ -503,18 +503,18 @@ impl UserKeyChain { /// Iterates over all shared private accounts. pub fn shared_private_accounts_iter( &self, - ) -> impl Iterator { + ) -> impl Iterator { self.shared_private_accounts.iter() } /// Returns the sealing secret key for GMS distribution, if it exists. #[must_use] - pub const fn sealing_secret_key(&self) -> Option { - self.sealing_secret_key + pub const fn sealing_secret_key(&self) -> Option<&ViewingSecretKey> { + self.sealing_secret_key.as_ref() } /// Sets the sealing secret key for GMS distribution. - pub const fn set_sealing_secret_key(&mut self, key: nssa_core::encryption::Scalar) { + pub const fn set_sealing_secret_key(&mut self, key: ViewingSecretKey) { self.sealing_secret_key = Some(key); } @@ -584,7 +584,7 @@ impl UserKeyChain { KeyChainPersistentData { accounts, - sealing_secret_key: *sealing_secret_key, + sealing_secret_key: sealing_secret_key.clone(), group_key_holders: group_key_holders.clone(), shared_private_accounts: shared_private_accounts.clone(), } @@ -705,8 +705,8 @@ mod tests { fn add_imported_public_account() { let mut user_data = UserKeyChain::default(); - let private_key = nssa::PrivateKey::new_os_random(); - let account_id = AccountId::from(&nssa::PublicKey::new_from_private_key(&private_key)); + let private_key = lee::PrivateKey::new_os_random(); + let account_id = AccountId::from(&lee::PublicKey::new_from_private_key(&private_key)); user_data.add_imported_public_account(private_key); @@ -721,7 +721,7 @@ mod tests { let key_chain = KeyChain::new_os_random(); let account_id = AccountId::from((&key_chain.nullifier_public_key, 0)); - let account = nssa_core::account::Account::default(); + let account = lee_core::account::Account::default(); user_data.add_imported_private_account(key_chain, None, 0, account); @@ -736,11 +736,11 @@ mod tests { let key_chain = KeyChain::new_os_random(); let account_id = AccountId::from((&key_chain.nullifier_public_key, 0)); - let account = nssa_core::account::Account::default(); + let account = lee_core::account::Account::default(); user_data.add_imported_private_account(key_chain, None, 0, account.clone()); - let new_account = nssa_core::account::Account { + let new_account = lee_core::account::Account { balance: 100, ..account }; @@ -761,9 +761,9 @@ mod tests { let (account_id, _chain_index) = user_data .generate_new_privacy_preserving_transaction_key_chain(Some(ChainIndex::root())); - let new_account = nssa_core::account::Account { + let new_account = lee_core::account::Account { balance: 100, - ..nssa_core::account::Account::default() + ..lee_core::account::Account::default() }; user_data @@ -782,9 +782,9 @@ mod tests { let key_chain = KeyChain::new_os_random(); let account_id = AccountId::from((&key_chain.nullifier_public_key, 0)); - let new_account = nssa_core::account::Account { + let new_account = lee_core::account::Account { balance: 100, - ..nssa_core::account::Account::default() + ..lee_core::account::Account::default() }; let result = user_data.insert_private_account( @@ -802,7 +802,7 @@ mod tests { let key_chain = KeyChain::new_os_random(); let account_id1 = AccountId::from((&key_chain.nullifier_public_key, 0)); - let account = nssa_core::account::Account::default(); + let account = lee_core::account::Account::default(); user_data.add_imported_private_account(key_chain, None, 0, account); let (account_id2, chain_index2) = user_data @@ -852,14 +852,14 @@ mod tests { #[test] fn shared_account_entry_serde_round_trip() { - use nssa_core::program::PdaSeed; + use lee_core::program::PdaSeed; let entry = SharedAccountEntry { group_label: Label::new("test-group"), identifier: 42, pda_seed: None, authority_program_id: None, - account: nssa_core::account::Account::default(), + account: lee_core::account::Account::default(), }; let encoded = bincode::serialize(&entry).expect("serialize"); let decoded: SharedAccountEntry = bincode::deserialize(&encoded).expect("deserialize"); @@ -872,7 +872,7 @@ mod tests { identifier: u128::MAX, pda_seed: Some(PdaSeed::new([7_u8; 32])), authority_program_id: Some([9; 8]), - account: nssa_core::account::Account::default(), + account: lee_core::account::Account::default(), }; let pda_encoded = bincode::serialize(&pda_entry).expect("serialize pda"); let pda_decoded: SharedAccountEntry = @@ -891,7 +891,7 @@ mod tests { identifier: 1, pda_seed: None, authority_program_id: None, - account: nssa_core::account::Account::default(), + account: lee_core::account::Account::default(), }; let encoded = bincode::serialize(&entry).expect("serialize"); let decoded: SharedAccountEntry = bincode::deserialize(&encoded).expect("deserialize"); @@ -902,7 +902,7 @@ mod tests { #[test] fn shared_account_derives_consistent_keys_from_group() { - use nssa_core::program::PdaSeed; + use lee_core::program::PdaSeed; let mut user_data = UserKeyChain::default(); let gms_holder = GroupKeyHolder::from_gms([42_u8; 32]); diff --git a/wallet/src/storage/persistent.rs b/lez/wallet/src/storage/persistent.rs similarity index 88% rename from wallet/src/storage/persistent.rs rename to lez/wallet/src/storage/persistent.rs index 0c82ceaa..01d6b166 100644 --- a/wallet/src/storage/persistent.rs +++ b/lez/wallet/src/storage/persistent.rs @@ -5,6 +5,7 @@ use key_protocol::key_management::{ key_tree::{ chain_index::ChainIndex, keys_private::ChildKeysPrivate, keys_public::ChildKeysPublic, }, + secret_holders::ViewingSecretKey, }; use serde::{Deserialize, Serialize}; use testnet_initial_state::{PrivateAccountPrivateInitialData, PublicAccountPrivateInitialData}; @@ -26,11 +27,11 @@ pub struct PersistentStorage { pub struct KeyChainPersistentData { pub accounts: Vec, #[serde(default)] - pub sealing_secret_key: Option, + pub sealing_secret_key: Option, #[serde(default)] pub group_key_holders: BTreeMap, #[serde(default)] - pub shared_private_accounts: BTreeMap, + pub shared_private_accounts: BTreeMap, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -43,14 +44,14 @@ pub enum PersistentAccountData { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct PersistentAccountDataPublic { - pub account_id: nssa::AccountId, + pub account_id: lee::AccountId, pub chain_index: ChainIndex, pub data: ChildKeysPublic, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct PersistentAccountDataPrivate { - pub account_id: nssa::AccountId, + pub account_id: lee::AccountId, pub chain_index: ChainIndex, pub data: ChildKeysPrivatePersistent, } @@ -59,7 +60,7 @@ pub struct PersistentAccountDataPrivate { pub struct ChildKeysPrivatePersistent { pub value: ( key_protocol::key_management::KeyChain, - Vec<(nssa_core::PrivateAccountKind, nssa::Account)>, + Vec<(lee_core::PrivateAccountKind, lee::Account)>, ), pub ccc: [u8; 32], pub cci: Option, diff --git a/nssa/core/src/encryption/shared_key_derivation.rs b/nssa/core/src/encryption/shared_key_derivation.rs deleted file mode 100644 index 8ea5aac8..00000000 --- a/nssa/core/src/encryption/shared_key_derivation.rs +++ /dev/null @@ -1,78 +0,0 @@ -#![expect( - clippy::arithmetic_side_effects, - reason = "Multiplication of finite field elements can't overflow" -)] - -use std::fmt::Write as _; - -use borsh::{BorshDeserialize, BorshSerialize}; -use k256::{ - AffinePoint, EncodedPoint, FieldBytes, ProjectivePoint, - elliptic_curve::{ - PrimeField as _, - sec1::{FromEncodedPoint as _, ToEncodedPoint as _}, - }, -}; -use serde::{Deserialize, Serialize}; - -use crate::{SharedSecretKey, encryption::Scalar}; - -#[derive( - Serialize, Deserialize, Clone, PartialEq, Eq, PartialOrd, Ord, BorshSerialize, BorshDeserialize, -)] -pub struct Secp256k1Point(pub Vec); - -impl std::fmt::Debug for Secp256k1Point { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let hex: String = self.0.iter().fold(String::new(), |mut acc, b| { - write!(acc, "{b:02x}").expect("writing to string should not fail"); - acc - }); - write!(f, "Secp256k1Point({hex})") - } -} - -impl Secp256k1Point { - #[must_use] - pub fn from_scalar(value: Scalar) -> Self { - let x_bytes: FieldBytes = value.into(); - let x = k256::Scalar::from_repr(x_bytes).unwrap(); - - let p = ProjectivePoint::GENERATOR * x; - let q = AffinePoint::from(p); - let enc = q.to_encoded_point(true); - - Self(enc.as_bytes().to_vec()) - } -} - -pub type EphemeralSecretKey = Scalar; -pub type EphemeralPublicKey = Secp256k1Point; -pub type ViewingPublicKey = Secp256k1Point; -impl From<&EphemeralSecretKey> for EphemeralPublicKey { - fn from(value: &EphemeralSecretKey) -> Self { - Self::from_scalar(*value) - } -} - -impl SharedSecretKey { - /// Creates a new shared secret key from a scalar and a point. - #[must_use] - pub fn new(scalar: Scalar, point: &Secp256k1Point) -> Self { - let scalar = k256::Scalar::from_repr(scalar.into()).unwrap(); - let point: [u8; 33] = point.0.clone().try_into().unwrap(); - - let encoded = EncodedPoint::from_bytes(point).unwrap(); - let pubkey_affine = AffinePoint::from_encoded_point(&encoded).unwrap(); - - let shared = ProjectivePoint::from(pubkey_affine) * scalar; - let shared_affine = shared.to_affine(); - - let shared_affine_encoded = shared_affine.to_encoded_point(false); - let x_bytes_slice = shared_affine_encoded.x().unwrap(); - let mut x_bytes = [0_u8; 32]; - x_bytes.copy_from_slice(x_bytes_slice); - - Self(x_bytes) - } -} diff --git a/program_methods/guest/Cargo.toml b/program_methods/guest/Cargo.toml index 136fb0b8..b7b37961 100644 --- a/program_methods/guest/Cargo.toml +++ b/program_methods/guest/Cargo.toml @@ -8,7 +8,7 @@ license = { workspace = true } workspace = true [dependencies] -nssa_core.workspace = true +lee_core.workspace = true authenticated_transfer_core.workspace = true clock_core.workspace = true token_core.workspace = true @@ -18,6 +18,7 @@ amm_program.workspace = true ata_core.workspace = true ata_program.workspace = true faucet_core.workspace = true +bridge_core.workspace = true vault_core.workspace = true risc0-zkvm.workspace = true serde = { workspace = true, default-features = false } diff --git a/program_methods/guest/src/bin/amm.rs b/program_methods/guest/src/bin/amm.rs index bce76c63..9d4afc63 100644 --- a/program_methods/guest/src/bin/amm.rs +++ b/program_methods/guest/src/bin/amm.rs @@ -9,7 +9,7 @@ use std::num::NonZero; use amm_core::Instruction; -use nssa_core::program::{ProgramInput, ProgramOutput, read_nssa_inputs}; +use lee_core::program::{ProgramInput, ProgramOutput, read_lee_inputs}; fn main() { let ( @@ -20,7 +20,7 @@ fn main() { instruction, }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let pre_states_clone = pre_states.clone(); diff --git a/program_methods/guest/src/bin/associated_token_account.rs b/program_methods/guest/src/bin/associated_token_account.rs index 9b155d7f..a32bbf9b 100644 --- a/program_methods/guest/src/bin/associated_token_account.rs +++ b/program_methods/guest/src/bin/associated_token_account.rs @@ -1,5 +1,5 @@ use ata_core::Instruction; -use nssa_core::program::{ProgramInput, ProgramOutput, read_nssa_inputs}; +use lee_core::program::{ProgramInput, ProgramOutput, read_lee_inputs}; fn main() { let ( @@ -10,7 +10,7 @@ fn main() { instruction, }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let pre_states_clone = pre_states.clone(); diff --git a/program_methods/guest/src/bin/authenticated_transfer.rs b/program_methods/guest/src/bin/authenticated_transfer.rs index 0c8040d9..cb535039 100644 --- a/program_methods/guest/src/bin/authenticated_transfer.rs +++ b/program_methods/guest/src/bin/authenticated_transfer.rs @@ -1,8 +1,8 @@ use authenticated_transfer_core::Instruction; -use nssa_core::{ +use lee_core::{ account::{Account, AccountWithMetadata}, program::{ - AccountPostState, Claim, DEFAULT_PROGRAM_ID, ProgramInput, ProgramOutput, read_nssa_inputs, + AccountPostState, Claim, DEFAULT_PROGRAM_ID, ProgramInput, ProgramOutput, read_lee_inputs, }, }; @@ -70,7 +70,7 @@ fn main() { instruction, }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let post_states = match instruction { Instruction::Initialize => { diff --git a/program_methods/guest/src/bin/bridge.rs b/program_methods/guest/src/bin/bridge.rs new file mode 100644 index 00000000..eb082c7c --- /dev/null +++ b/program_methods/guest/src/bin/bridge.rs @@ -0,0 +1,83 @@ +use bridge_core::Instruction; +use lee_core::program::{ + AccountPostState, ChainedCall, ProgramInput, ProgramOutput, read_lee_inputs, +}; + +fn unchanged_post_states( + pre_states: &[lee_core::account::AccountWithMetadata], +) -> Vec { + pre_states + .iter() + .map(|pre_state| AccountPostState::new(pre_state.account.clone())) + .collect() +} + +fn main() { + let ( + ProgramInput { + self_program_id, + caller_program_id, + pre_states, + instruction, + }, + instruction_words, + ) = read_lee_inputs::(); + + assert!( + caller_program_id.is_none(), + "Bridge cannot be invoked through chain calls" + ); + + let pre_states_clone = pre_states.clone(); + let post_states = unchanged_post_states(&pre_states_clone); + + let chained_calls = match instruction { + Instruction::Deposit { + l1_deposit_op_id: _, + vault_program_id, + recipient_id, + amount, + } => { + let [bridge, recipient_vault] = pre_states + .try_into() + .expect("Deposit requires exactly 2 accounts"); + + assert_eq!( + bridge.account_id, + bridge_core::compute_bridge_account_id(self_program_id), + "First account must be bridge PDA" + ); + + assert_eq!( + recipient_vault.account_id, + vault_core::compute_vault_account_id(vault_program_id, recipient_id), + "Second account must be recipient vault PDA" + ); + + let mut bridge_for_vault = bridge; + bridge_for_vault.is_authorized = true; + + vec![ + ChainedCall::new( + vault_program_id, + vec![bridge_for_vault, recipient_vault], + &vault_core::Instruction::Transfer { + recipient_id, + amount, + }, + ) + .with_pda_seeds(vec![bridge_core::compute_bridge_seed()]), + ] + } + }; + + ProgramOutput::new( + self_program_id, + caller_program_id, + instruction_words, + pre_states_clone, + post_states, + ) + .with_chained_calls(chained_calls) + .write(); +} diff --git a/program_methods/guest/src/bin/clock.rs b/program_methods/guest/src/bin/clock.rs index cb49c384..989394f7 100644 --- a/program_methods/guest/src/bin/clock.rs +++ b/program_methods/guest/src/bin/clock.rs @@ -12,9 +12,9 @@ use clock_core::{ CLOCK_01_PROGRAM_ACCOUNT_ID, CLOCK_10_PROGRAM_ACCOUNT_ID, CLOCK_50_PROGRAM_ACCOUNT_ID, ClockAccountData, Instruction, }; -use nssa_core::{ +use lee_core::{ account::AccountWithMetadata, - program::{AccountPostState, ProgramInput, ProgramOutput, read_nssa_inputs}, + program::{AccountPostState, ProgramInput, ProgramOutput, read_lee_inputs}, }; fn update_if_multiple( @@ -45,7 +45,7 @@ fn main() { instruction: timestamp, }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let Ok([pre_01, pre_10, pre_50]) = <[_; 3]>::try_from(pre_states) else { panic!("Invalid number of input accounts"); diff --git a/program_methods/guest/src/bin/faucet.rs b/program_methods/guest/src/bin/faucet.rs index e56330cd..2a148000 100644 --- a/program_methods/guest/src/bin/faucet.rs +++ b/program_methods/guest/src/bin/faucet.rs @@ -1,10 +1,10 @@ use faucet_core::Instruction; -use nssa_core::program::{ - AccountPostState, ChainedCall, ProgramInput, ProgramOutput, read_nssa_inputs, +use lee_core::program::{ + AccountPostState, ChainedCall, ProgramInput, ProgramOutput, read_lee_inputs, }; fn unchanged_post_states( - pre_states: &[nssa_core::account::AccountWithMetadata], + pre_states: &[lee_core::account::AccountWithMetadata], ) -> Vec { pre_states .iter() @@ -21,13 +21,18 @@ fn main() { instruction, }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); + + assert!( + caller_program_id.is_none(), + "Faucet cannot be invoked through chain calls" + ); let pre_states_clone = pre_states.clone(); let post_states = unchanged_post_states(&pre_states_clone); let chained_calls = match instruction { - Instruction::Transfer { + Instruction::GenesisTransferVault { vault_program_id, recipient_id, amount, @@ -57,6 +62,29 @@ fn main() { .with_pda_seeds(vec![faucet_core::compute_faucet_seed()]), ] } + Instruction::GenesisTransferDirect { amount } => { + let [faucet, recipient] = pre_states + .try_into() + .expect("TransferDirect requires exactly 2 accounts"); + + assert_eq!( + faucet.account_id, + faucet_core::compute_faucet_account_id(self_program_id), + "First account must be faucet PDA" + ); + + let mut faucet_for_transfer = faucet; + faucet_for_transfer.is_authorized = true; + + vec![ + ChainedCall::new( + faucet_for_transfer.account.program_owner, + vec![faucet_for_transfer, recipient], + &authenticated_transfer_core::Instruction::Transfer { amount }, + ) + .with_pda_seeds(vec![faucet_core::compute_faucet_seed()]), + ] + } }; ProgramOutput::new( diff --git a/program_methods/guest/src/bin/pinata.rs b/program_methods/guest/src/bin/pinata.rs index dcc76397..cb8df931 100644 --- a/program_methods/guest/src/bin/pinata.rs +++ b/program_methods/guest/src/bin/pinata.rs @@ -1,4 +1,4 @@ -use nssa_core::program::{AccountPostState, Claim, ProgramInput, ProgramOutput, read_nssa_inputs}; +use lee_core::program::{AccountPostState, Claim, ProgramInput, ProgramOutput, read_lee_inputs}; use risc0_zkvm::sha::{Impl, Sha256 as _}; const PRIZE: u128 = 150; @@ -52,7 +52,7 @@ fn main() { instruction: solution, }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let Ok([pinata, winner]) = <[_; 2]>::try_from(pre_states) else { return; diff --git a/program_methods/guest/src/bin/pinata_token.rs b/program_methods/guest/src/bin/pinata_token.rs index 1f7ad9da..784112cb 100644 --- a/program_methods/guest/src/bin/pinata_token.rs +++ b/program_methods/guest/src/bin/pinata_token.rs @@ -1,7 +1,7 @@ -use nssa_core::{ +use lee_core::{ account::Data, program::{ - AccountPostState, ChainedCall, PdaSeed, ProgramInput, ProgramOutput, read_nssa_inputs, + AccountPostState, ChainedCall, PdaSeed, ProgramInput, ProgramOutput, read_lee_inputs, }, }; use risc0_zkvm::sha::{Impl, Sha256 as _}; @@ -58,7 +58,7 @@ fn main() { instruction: solution, }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let Ok( [ diff --git a/program_methods/guest/src/bin/privacy_preserving_circuit/execution_state.rs b/program_methods/guest/src/bin/privacy_preserving_circuit/execution_state.rs index c06698d6..8d920068 100644 --- a/program_methods/guest/src/bin/privacy_preserving_circuit/execution_state.rs +++ b/program_methods/guest/src/bin/privacy_preserving_circuit/execution_state.rs @@ -3,7 +3,7 @@ use std::{ convert::Infallible, }; -use nssa_core::{ +use lee_core::{ Identifier, InputAccountIdentity, NullifierPublicKey, account::{Account, AccountId, AccountWithMetadata}, program::{ diff --git a/program_methods/guest/src/bin/privacy_preserving_circuit/main.rs b/program_methods/guest/src/bin/privacy_preserving_circuit/main.rs index 9441c27e..a342665d 100644 --- a/program_methods/guest/src/bin/privacy_preserving_circuit/main.rs +++ b/program_methods/guest/src/bin/privacy_preserving_circuit/main.rs @@ -1,4 +1,4 @@ -use nssa_core::PrivacyPreservingCircuitInput; +use lee_core::PrivacyPreservingCircuitInput; use risc0_zkvm::guest::env; mod execution_state; diff --git a/program_methods/guest/src/bin/privacy_preserving_circuit/output.rs b/program_methods/guest/src/bin/privacy_preserving_circuit/output.rs index 6e302401..621a461c 100644 --- a/program_methods/guest/src/bin/privacy_preserving_circuit/output.rs +++ b/program_methods/guest/src/bin/privacy_preserving_circuit/output.rs @@ -1,4 +1,4 @@ -use nssa_core::{ +use lee_core::{ Commitment, CommitmentSetDigest, DUMMY_COMMITMENT_HASH, EncryptionScheme, InputAccountIdentity, MembershipProof, Nullifier, NullifierPublicKey, NullifierSecretKey, PrivacyPreservingCircuitOutput, PrivateAccountKind, SharedSecretKey, @@ -62,7 +62,7 @@ pub fn compute_circuit_output( Nullifier::for_account_initialization(&account_id), DUMMY_COMMITMENT_HASH, ); - let new_nonce = pre_state.account.nonce.private_account_nonce_increment(nsk); + let new_nonce = Nonce::private_account_nonce_init(&account_id); emit_private_output( &mut output, diff --git a/program_methods/guest/src/bin/token.rs b/program_methods/guest/src/bin/token.rs index 68205d77..6e5cb8df 100644 --- a/program_methods/guest/src/bin/token.rs +++ b/program_methods/guest/src/bin/token.rs @@ -6,7 +6,7 @@ //! Token program accepts [`Instruction`] as input, refer to the corresponding documentation //! for more details. -use nssa_core::program::{ProgramInput, ProgramOutput, read_nssa_inputs}; +use lee_core::program::{ProgramInput, ProgramOutput, read_lee_inputs}; use token_program::core::Instruction; fn main() { @@ -18,7 +18,7 @@ fn main() { instruction, }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let pre_states_clone = pre_states.clone(); diff --git a/program_methods/guest/src/bin/vault.rs b/program_methods/guest/src/bin/vault.rs index c56c1a7f..92924866 100644 --- a/program_methods/guest/src/bin/vault.rs +++ b/program_methods/guest/src/bin/vault.rs @@ -5,13 +5,13 @@ //! performs the actual transfer of funds from the vault accounts. use authenticated_transfer_core::Instruction as AuthTransferInstruction; -use nssa_core::program::{ - AccountPostState, ChainedCall, ProgramInput, ProgramOutput, read_nssa_inputs, +use lee_core::program::{ + AccountPostState, ChainedCall, ProgramInput, ProgramOutput, read_lee_inputs, }; use vault_core::Instruction; fn unchanged_post_states( - pre_states: &[nssa_core::account::AccountWithMetadata], + pre_states: &[lee_core::account::AccountWithMetadata], ) -> Vec { pre_states .iter() @@ -28,7 +28,7 @@ fn main() { instruction, }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let pre_states_clone = pre_states.clone(); let post_states = unchanged_post_states(&pre_states_clone); diff --git a/programs/amm/Cargo.toml b/programs/amm/Cargo.toml index 4fcadb9f..5a4be879 100644 --- a/programs/amm/Cargo.toml +++ b/programs/amm/Cargo.toml @@ -8,9 +8,9 @@ license = { workspace = true } workspace = true [dependencies] -nssa_core.workspace = true +lee_core.workspace = true token_core.workspace = true amm_core.workspace = true [dev-dependencies] -nssa = { workspace = true, features = ["test-utils"] } +lee = { workspace = true, features = ["test-utils"] } diff --git a/programs/amm/core/Cargo.toml b/programs/amm/core/Cargo.toml index b9c59dc4..eb0d54eb 100644 --- a/programs/amm/core/Cargo.toml +++ b/programs/amm/core/Cargo.toml @@ -8,7 +8,7 @@ license = { workspace = true } workspace = true [dependencies] -nssa_core.workspace = true +lee_core.workspace = true serde.workspace = true risc0-zkvm.workspace = true borsh.workspace = true diff --git a/programs/amm/core/src/lib.rs b/programs/amm/core/src/lib.rs index 6e005c9e..54f93ca4 100644 --- a/programs/amm/core/src/lib.rs +++ b/programs/amm/core/src/lib.rs @@ -1,7 +1,7 @@ //! This crate contains core data structures and utilities for the AMM Program. use borsh::{BorshDeserialize, BorshSerialize}; -use nssa_core::{ +use lee_core::{ account::{AccountId, Data}, program::{PdaSeed, ProgramId}, }; diff --git a/programs/amm/src/add.rs b/programs/amm/src/add.rs index d057507b..807f04d0 100644 --- a/programs/amm/src/add.rs +++ b/programs/amm/src/add.rs @@ -1,7 +1,7 @@ use std::num::NonZeroU128; use amm_core::{PoolDefinition, compute_liquidity_token_pda_seed}; -use nssa_core::{ +use lee_core::{ account::{AccountWithMetadata, Data}, program::{AccountPostState, ChainedCall}, }; diff --git a/programs/amm/src/new_definition.rs b/programs/amm/src/new_definition.rs index 88263b87..a6111967 100644 --- a/programs/amm/src/new_definition.rs +++ b/programs/amm/src/new_definition.rs @@ -4,7 +4,7 @@ use amm_core::{ PoolDefinition, compute_liquidity_token_pda, compute_liquidity_token_pda_seed, compute_pool_pda, compute_pool_pda_seed, compute_vault_pda, compute_vault_pda_seed, }; -use nssa_core::{ +use lee_core::{ account::{Account, AccountWithMetadata, Data}, program::{AccountPostState, ChainedCall, Claim, ProgramId}, }; diff --git a/programs/amm/src/remove.rs b/programs/amm/src/remove.rs index 7844f4bd..5c492509 100644 --- a/programs/amm/src/remove.rs +++ b/programs/amm/src/remove.rs @@ -1,7 +1,7 @@ use std::num::NonZeroU128; use amm_core::{PoolDefinition, compute_liquidity_token_pda_seed, compute_vault_pda_seed}; -use nssa_core::{ +use lee_core::{ account::{AccountWithMetadata, Data}, program::{AccountPostState, ChainedCall}, }; diff --git a/programs/amm/src/swap.rs b/programs/amm/src/swap.rs index 22f3792a..a76d5bcf 100644 --- a/programs/amm/src/swap.rs +++ b/programs/amm/src/swap.rs @@ -1,5 +1,5 @@ pub use amm_core::{PoolDefinition, compute_liquidity_token_pda_seed, compute_vault_pda_seed}; -use nssa_core::{ +use lee_core::{ account::{AccountId, AccountWithMetadata, Data}, program::{AccountPostState, ChainedCall}, }; diff --git a/programs/amm/src/tests.rs b/programs/amm/src/tests.rs index a10a985d..d93bedb2 100644 --- a/programs/amm/src/tests.rs +++ b/programs/amm/src/tests.rs @@ -4,10 +4,10 @@ use amm_core::{ PoolDefinition, compute_liquidity_token_pda, compute_liquidity_token_pda_seed, compute_pool_pda, compute_vault_pda, compute_vault_pda_seed, }; -use nssa::{ +use lee::{ PrivateKey, PublicKey, PublicTransaction, V03State, program::Program, public_transaction, }; -use nssa_core::{ +use lee_core::{ account::{Account, AccountId, AccountWithMetadata, Data}, program::{ChainedCall, ProgramId}, }; diff --git a/programs/associated_token_account/Cargo.toml b/programs/associated_token_account/Cargo.toml index 98e0bfd0..b6be7155 100644 --- a/programs/associated_token_account/Cargo.toml +++ b/programs/associated_token_account/Cargo.toml @@ -5,6 +5,6 @@ edition = "2024" license = { workspace = true } [dependencies] -nssa_core.workspace = true +lee_core.workspace = true token_core.workspace = true ata_core.workspace = true diff --git a/programs/associated_token_account/core/Cargo.toml b/programs/associated_token_account/core/Cargo.toml index 7ca8d7fa..9c80e897 100644 --- a/programs/associated_token_account/core/Cargo.toml +++ b/programs/associated_token_account/core/Cargo.toml @@ -5,6 +5,6 @@ edition = "2024" license = { workspace = true } [dependencies] -nssa_core.workspace = true +lee_core.workspace = true serde.workspace = true risc0-zkvm.workspace = true diff --git a/programs/associated_token_account/core/src/lib.rs b/programs/associated_token_account/core/src/lib.rs index 77900a2c..95dfe516 100644 --- a/programs/associated_token_account/core/src/lib.rs +++ b/programs/associated_token_account/core/src/lib.rs @@ -1,5 +1,5 @@ -pub use nssa_core::program::PdaSeed; -use nssa_core::{ +pub use lee_core::program::PdaSeed; +use lee_core::{ account::{AccountId, AccountWithMetadata}, program::ProgramId, }; diff --git a/programs/associated_token_account/src/burn.rs b/programs/associated_token_account/src/burn.rs index 4940fdeb..2aae0dd2 100644 --- a/programs/associated_token_account/src/burn.rs +++ b/programs/associated_token_account/src/burn.rs @@ -1,4 +1,4 @@ -use nssa_core::{ +use lee_core::{ account::AccountWithMetadata, program::{AccountPostState, ChainedCall, ProgramId}, }; diff --git a/programs/associated_token_account/src/create.rs b/programs/associated_token_account/src/create.rs index d44f5d1c..c910ab5b 100644 --- a/programs/associated_token_account/src/create.rs +++ b/programs/associated_token_account/src/create.rs @@ -1,4 +1,4 @@ -use nssa_core::{ +use lee_core::{ account::{Account, AccountWithMetadata}, program::{AccountPostState, ChainedCall, Claim, ProgramId}, }; diff --git a/programs/associated_token_account/src/tests.rs b/programs/associated_token_account/src/tests.rs index 9835bf37..7717eae1 100644 --- a/programs/associated_token_account/src/tests.rs +++ b/programs/associated_token_account/src/tests.rs @@ -1,11 +1,11 @@ #![cfg(test)] use ata_core::{compute_ata_seed, get_associated_token_account_id}; -use nssa_core::account::{Account, AccountId, AccountWithMetadata, Data}; +use lee_core::account::{Account, AccountId, AccountWithMetadata, Data}; use token_core::{TokenDefinition, TokenHolding}; -const ATA_PROGRAM_ID: nssa_core::program::ProgramId = [1u32; 8]; -const TOKEN_PROGRAM_ID: nssa_core::program::ProgramId = [2u32; 8]; +const ATA_PROGRAM_ID: lee_core::program::ProgramId = [1u32; 8]; +const TOKEN_PROGRAM_ID: lee_core::program::ProgramId = [2u32; 8]; fn owner_id() -> AccountId { AccountId::new([0x01u8; 32]) @@ -40,7 +40,7 @@ fn definition_account() -> AccountWithMetadata { total_supply: 1000, metadata_id: None, }), - nonce: nssa_core::account::Nonce(0), + nonce: lee_core::account::Nonce(0), }, is_authorized: false, account_id: definition_id(), @@ -64,7 +64,7 @@ fn initialized_ata_account() -> AccountWithMetadata { definition_id: definition_id(), balance: 100, }), - nonce: nssa_core::account::Nonce(0), + nonce: lee_core::account::Nonce(0), }, is_authorized: false, account_id: ata_id(), diff --git a/programs/associated_token_account/src/transfer.rs b/programs/associated_token_account/src/transfer.rs index 89d70135..cd76292f 100644 --- a/programs/associated_token_account/src/transfer.rs +++ b/programs/associated_token_account/src/transfer.rs @@ -1,4 +1,4 @@ -use nssa_core::{ +use lee_core::{ account::AccountWithMetadata, program::{AccountPostState, ChainedCall, ProgramId}, }; diff --git a/programs/bridge/core/Cargo.toml b/programs/bridge/core/Cargo.toml new file mode 100644 index 00000000..201e899f --- /dev/null +++ b/programs/bridge/core/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "bridge_core" +version = "0.1.0" +edition = "2024" +license = { workspace = true } + +[lints] +workspace = true + +[dependencies] +lee_core.workspace = true +serde = { workspace = true, default-features = false } diff --git a/programs/bridge/core/src/lib.rs b/programs/bridge/core/src/lib.rs new file mode 100644 index 00000000..1e1bff4f --- /dev/null +++ b/programs/bridge/core/src/lib.rs @@ -0,0 +1,32 @@ +pub use lee_core::program::PdaSeed; +use lee_core::{account::AccountId, program::ProgramId}; +use serde::{Deserialize, Serialize}; + +const BRIDGE_SEED_DOMAIN_SEPARATOR: [u8; 32] = *b"/LEZ/v0.3/BridgeSeed/0000000000/"; + +#[derive(Serialize, Deserialize)] +pub enum Instruction { + /// Transfers native tokens from the bridge PDA account to a recipient vault. + /// + /// Required accounts (2): + /// - Bridge PDA account + /// - Recipient vault PDA account + Deposit { + /// Deposit OP ID from L1, stored here to pin each [`Deposit`](Instruction::Deposit) to a + /// Deposit Event on L1. + l1_deposit_op_id: [u8; 32], + vault_program_id: ProgramId, + recipient_id: AccountId, + amount: u128, + }, +} + +#[must_use] +pub const fn compute_bridge_seed() -> PdaSeed { + PdaSeed::new(BRIDGE_SEED_DOMAIN_SEPARATOR) +} + +#[must_use] +pub fn compute_bridge_account_id(bridge_program_id: ProgramId) -> AccountId { + AccountId::for_public_pda(&bridge_program_id, &compute_bridge_seed()) +} diff --git a/programs/clock/core/Cargo.toml b/programs/clock/core/Cargo.toml index 53a43b6d..69065b50 100644 --- a/programs/clock/core/Cargo.toml +++ b/programs/clock/core/Cargo.toml @@ -8,5 +8,5 @@ license = { workspace = true } workspace = true [dependencies] -nssa_core.workspace = true +lee_core.workspace = true borsh.workspace = true diff --git a/programs/clock/core/src/lib.rs b/programs/clock/core/src/lib.rs index 5fc03633..711db419 100644 --- a/programs/clock/core/src/lib.rs +++ b/programs/clock/core/src/lib.rs @@ -1,7 +1,7 @@ //! Core data structures and constants for the Clock Program. use borsh::{BorshDeserialize, BorshSerialize}; -use nssa_core::{Timestamp, account::AccountId}; +use lee_core::{Timestamp, account::AccountId}; pub const CLOCK_01_PROGRAM_ACCOUNT_ID: AccountId = AccountId::new(*b"/LEZ/ClockProgramAccount/0000001"); diff --git a/programs/faucet/core/Cargo.toml b/programs/faucet/core/Cargo.toml index aa8826ea..004b1e4e 100644 --- a/programs/faucet/core/Cargo.toml +++ b/programs/faucet/core/Cargo.toml @@ -8,5 +8,5 @@ license = { workspace = true } workspace = true [dependencies] -nssa_core.workspace = true +lee_core.workspace = true serde = { workspace = true, default-features = false } diff --git a/programs/faucet/core/src/lib.rs b/programs/faucet/core/src/lib.rs index da9861e6..6a3ae4ad 100644 --- a/programs/faucet/core/src/lib.rs +++ b/programs/faucet/core/src/lib.rs @@ -1,5 +1,5 @@ -pub use nssa_core::program::PdaSeed; -use nssa_core::{account::AccountId, program::ProgramId}; +pub use lee_core::program::PdaSeed; +use lee_core::{account::AccountId, program::ProgramId}; use serde::{Deserialize, Serialize}; const FAUCET_SEED_DOMAIN_SEPARATOR: [u8; 32] = *b"/LEZ/v0.3/FaucetSeed/0000000000/"; @@ -8,14 +8,25 @@ const FAUCET_SEED_DOMAIN_SEPARATOR: [u8; 32] = *b"/LEZ/v0.3/FaucetSeed/000000000 pub enum Instruction { /// Transfers native tokens from system faucet to recipient's vault. /// + /// Executed only in genesis block by sequencer it-self. User transactions will be denied. + /// /// Required accounts (2): /// - Faucet PDA account /// - Recipient vault PDA account - Transfer { + GenesisTransferVault { vault_program_id: ProgramId, recipient_id: AccountId, amount: u128, }, + + /// Transfers native tokens from system faucet directly to a recipient account. + /// + /// Executed only in genesis block by sequencer it-self. User transactions will be denied. + /// + /// Required accounts (2): + /// - Faucet PDA account + /// - Recipient account + GenesisTransferDirect { amount: u128 }, } #[must_use] diff --git a/programs/token/Cargo.toml b/programs/token/Cargo.toml index 57c88b7b..2b23a9eb 100644 --- a/programs/token/Cargo.toml +++ b/programs/token/Cargo.toml @@ -8,5 +8,5 @@ license = { workspace = true } workspace = true [dependencies] -nssa_core.workspace = true +lee_core.workspace = true token_core.workspace = true diff --git a/programs/token/core/Cargo.toml b/programs/token/core/Cargo.toml index 90df286f..0464940c 100644 --- a/programs/token/core/Cargo.toml +++ b/programs/token/core/Cargo.toml @@ -8,6 +8,6 @@ license = { workspace = true } workspace = true [dependencies] -nssa_core.workspace = true +lee_core.workspace = true serde.workspace = true borsh.workspace = true diff --git a/programs/token/core/src/lib.rs b/programs/token/core/src/lib.rs index 79f49303..68cf3a47 100644 --- a/programs/token/core/src/lib.rs +++ b/programs/token/core/src/lib.rs @@ -1,7 +1,7 @@ //! This crate contains core data structures and utilities for the Token Program. use borsh::{BorshDeserialize, BorshSerialize}; -use nssa_core::account::{AccountId, Data}; +use lee_core::account::{AccountId, Data}; use serde::{Deserialize, Serialize}; /// Token Program Instruction. diff --git a/programs/token/src/burn.rs b/programs/token/src/burn.rs index a2468055..d7bfd0e0 100644 --- a/programs/token/src/burn.rs +++ b/programs/token/src/burn.rs @@ -1,4 +1,4 @@ -use nssa_core::{ +use lee_core::{ account::{AccountWithMetadata, Data}, program::AccountPostState, }; diff --git a/programs/token/src/initialize.rs b/programs/token/src/initialize.rs index fabb8fd9..add91f7a 100644 --- a/programs/token/src/initialize.rs +++ b/programs/token/src/initialize.rs @@ -1,4 +1,4 @@ -use nssa_core::{ +use lee_core::{ account::{Account, AccountWithMetadata, Data}, program::{AccountPostState, Claim}, }; diff --git a/programs/token/src/mint.rs b/programs/token/src/mint.rs index 5a15d81f..2d4b0d1e 100644 --- a/programs/token/src/mint.rs +++ b/programs/token/src/mint.rs @@ -1,4 +1,4 @@ -use nssa_core::{ +use lee_core::{ account::{Account, AccountWithMetadata, Data}, program::{AccountPostState, Claim}, }; diff --git a/programs/token/src/new_definition.rs b/programs/token/src/new_definition.rs index ba510feb..0120b054 100644 --- a/programs/token/src/new_definition.rs +++ b/programs/token/src/new_definition.rs @@ -1,4 +1,4 @@ -use nssa_core::{ +use lee_core::{ account::{Account, AccountWithMetadata, Data}, program::{AccountPostState, Claim}, }; diff --git a/programs/token/src/print_nft.rs b/programs/token/src/print_nft.rs index 6bc9612d..7048c8c2 100644 --- a/programs/token/src/print_nft.rs +++ b/programs/token/src/print_nft.rs @@ -1,4 +1,4 @@ -use nssa_core::{ +use lee_core::{ account::{Account, AccountWithMetadata, Data}, program::{AccountPostState, Claim}, }; diff --git a/programs/token/src/tests.rs b/programs/token/src/tests.rs index 4c28d769..8510300e 100644 --- a/programs/token/src/tests.rs +++ b/programs/token/src/tests.rs @@ -5,7 +5,7 @@ reason = "We don't care about it in tests" )] -use nssa_core::{ +use lee_core::{ account::{Account, AccountId, AccountWithMetadata, Data}, program::Claim, }; diff --git a/programs/token/src/transfer.rs b/programs/token/src/transfer.rs index 2ffd2339..9982ce88 100644 --- a/programs/token/src/transfer.rs +++ b/programs/token/src/transfer.rs @@ -1,4 +1,4 @@ -use nssa_core::{ +use lee_core::{ account::{Account, AccountWithMetadata, Data}, program::{AccountPostState, Claim}, }; diff --git a/programs/vault/core/Cargo.toml b/programs/vault/core/Cargo.toml index fd3cdf96..b1800fdf 100644 --- a/programs/vault/core/Cargo.toml +++ b/programs/vault/core/Cargo.toml @@ -8,6 +8,6 @@ license = { workspace = true } workspace = true [dependencies] -nssa_core.workspace = true +lee_core.workspace = true serde = { workspace = true, default-features = false } risc0-zkvm.workspace = true diff --git a/programs/vault/core/src/lib.rs b/programs/vault/core/src/lib.rs index 8937e087..30cf09e6 100644 --- a/programs/vault/core/src/lib.rs +++ b/programs/vault/core/src/lib.rs @@ -1,5 +1,5 @@ -pub use nssa_core::program::PdaSeed; -use nssa_core::{account::AccountId, program::ProgramId}; +pub use lee_core::program::PdaSeed; +use lee_core::{account::AccountId, program::ProgramId}; use serde::{Deserialize, Serialize}; const VAULT_SEED_DOMAIN_SEPARATOR: &[u8] = b"/LEZ/v0.3/VaultSeed/00000000000/"; diff --git a/sequencer/service/protocol/src/lib.rs b/sequencer/service/protocol/src/lib.rs deleted file mode 100644 index ec0020ac..00000000 --- a/sequencer/service/protocol/src/lib.rs +++ /dev/null @@ -1,5 +0,0 @@ -//! Reexports of types used by sequencer rpc specification. - -pub use common::{HashType, block::Block, transaction::NSSATransaction}; -pub use nssa::{Account, AccountId, ProgramId}; -pub use nssa_core::{BlockId, Commitment, MembershipProof, account::Nonce}; diff --git a/test_fixtures/Cargo.toml b/test_fixtures/Cargo.toml index 1bfd2284..1585cd99 100644 --- a/test_fixtures/Cargo.toml +++ b/test_fixtures/Cargo.toml @@ -12,8 +12,8 @@ workspace = true common.workspace = true indexer_service.workspace = true key_protocol.workspace = true -nssa.workspace = true -nssa_core = { workspace = true, features = ["host"] } +lee.workspace = true +lee_core = { workspace = true, features = ["host"] } sequencer_core = { workspace = true, features = ["default", "testnet"] } sequencer_service.workspace = true sequencer_service_rpc = { workspace = true, features = ["client"] } diff --git a/test_fixtures/src/config.rs b/test_fixtures/src/config.rs index 00bdc74a..73cd775b 100644 --- a/test_fixtures/src/config.rs +++ b/test_fixtures/src/config.rs @@ -4,8 +4,8 @@ use anyhow::{Context as _, Result}; use bytesize::ByteSize; use indexer_service::{ChannelId, ClientConfig, IndexerConfig}; use key_protocol::key_management::KeyChain; -use nssa::{AccountId, PrivateKey, PublicKey}; -use nssa_core::Identifier; +use lee::{AccountId, PrivateKey, PublicKey}; +use lee_core::Identifier; use sequencer_core::config::{BedrockConfig, GenesisAction, SequencerConfig}; use url::Url; use wallet::config::WalletConfig; @@ -143,7 +143,12 @@ pub fn genesis_from_accounts( balance: account.balance, }); - public_genesis.chain(private_genesis).collect() + let supply_bridge_account = GenesisAction::SupplyBridgeAccount { balance: 1_000_000 }; + + public_genesis + .chain(private_genesis) + .chain(std::iter::once(supply_bridge_account)) + .collect() } pub fn wallet_config(sequencer_addr: SocketAddr) -> Result { @@ -184,7 +189,8 @@ pub fn addr_to_url(protocol: UrlProtocol, addr: SocketAddr) -> Result { url_string.parse().map_err(Into::into) } -fn bedrock_channel_id() -> ChannelId { +#[must_use] +pub fn bedrock_channel_id() -> ChannelId { let channel_id: [u8; 32] = [0_u8, 1] .repeat(16) .try_into() diff --git a/test_fixtures/src/lib.rs b/test_fixtures/src/lib.rs index b22b6fe7..c632ba94 100644 --- a/test_fixtures/src/lib.rs +++ b/test_fixtures/src/lib.rs @@ -4,12 +4,12 @@ use std::{net::SocketAddr, path::Path, sync::LazyLock}; use anyhow::{Context as _, Result}; -use common::{HashType, transaction::NSSATransaction}; +use common::{HashType, transaction::LeeTransaction}; use futures::FutureExt as _; use indexer_service::IndexerHandle; +use lee::{AccountId, PrivacyPreservingTransaction}; +use lee_core::Commitment; use log::{debug, error}; -use nssa::{AccountId, PrivacyPreservingTransaction}; -use nssa_core::Commitment; use sequencer_core::config::GenesisAction; use sequencer_service::SequencerHandle; use sequencer_service_rpc::{RpcClient as _, SequencerClient, SequencerClientBuilder}; @@ -32,9 +32,9 @@ pub mod setup; // TODO: Remove this and control time from tests pub const TIME_TO_WAIT_FOR_BLOCK_SECONDS: u64 = 12; -pub const NSSA_PROGRAM_FOR_TEST_DATA_CHANGER: &str = "data_changer.bin"; -pub const NSSA_PROGRAM_FOR_TEST_NOOP: &str = "noop.bin"; -pub const NSSA_PROGRAM_FOR_TEST_PDA_SPEND_PROXY: &str = "pda_spend_proxy.bin"; +pub const LEE_PROGRAM_FOR_TEST_DATA_CHANGER: &str = "data_changer.bin"; +pub const LEE_PROGRAM_FOR_TEST_NOOP: &str = "noop.bin"; +pub const LEE_PROGRAM_FOR_TEST_PDA_SPEND_PROXY: &str = "pda_spend_proxy.bin"; pub(crate) const BEDROCK_SERVICE_WITH_OPEN_PORT: &str = "logos-blockchain-node-0"; pub(crate) const BEDROCK_SERVICE_PORT: u16 = 18080; @@ -465,7 +465,7 @@ pub async fn fetch_privacy_preserving_tx( let tx = seq_client.get_transaction(tx_hash).await.unwrap().unwrap(); match tx { - NSSATransaction::PrivacyPreserving(privacy_preserving_transaction) => { + LeeTransaction::PrivacyPreserving(privacy_preserving_transaction) => { privacy_preserving_transaction } _ => panic!("Invalid tx type"), diff --git a/test_fixtures/src/setup.rs b/test_fixtures/src/setup.rs index 5d7377b1..597b0714 100644 --- a/test_fixtures/src/setup.rs +++ b/test_fixtures/src/setup.rs @@ -1,10 +1,10 @@ use std::{collections::HashMap, net::SocketAddr, path::PathBuf}; use anyhow::{Context as _, Result, bail}; -use common::transaction::NSSATransaction; +use common::transaction::LeeTransaction; use indexer_service::IndexerHandle; +use lee::{AccountId, PrivateKey, PublicKey, PublicTransaction, program::Program}; use log::{debug, warn}; -use nssa::{AccountId, PrivateKey, PublicKey, PublicTransaction, program::Program}; use sequencer_service::{GenesisAction, SequencerHandle}; use sequencer_service_rpc::RpcClient as _; use tempfile::TempDir; @@ -173,7 +173,7 @@ pub fn setup_wallet( private_account.key_chain.clone(), None, private_account.identifier, - nssa::Account::default(), + lee::Account::default(), ); } @@ -237,7 +237,7 @@ async fn claim_funds_from_vault( .pub_account_signing_key(owner_id) .with_context(|| format!("Missing signing key for public account {owner_id}"))?; - let message = nssa::public_transaction::Message::try_new( + let message = lee::public_transaction::Message::try_new( vault_program_id, vec![owner_id, owner_vault_id], nonces, @@ -245,12 +245,12 @@ async fn claim_funds_from_vault( ) .context("Failed to build vault claim message")?; - let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[signing_key]); + let witness_set = lee::public_transaction::WitnessSet::for_message(&message, &[signing_key]); let tx = PublicTransaction::new(message, witness_set); let tx_hash = wallet .sequencer_client - .send_transaction(NSSATransaction::Public(tx)) + .send_transaction(LeeTransaction::Public(tx)) .await .context("Failed to submit vault claim transaction")?; @@ -280,7 +280,7 @@ async fn claim_funds_from_vault_to_private( .context("Failed to serialize vault private claim instruction")?; let program_with_dependencies = - nssa::privacy_preserving_transaction::circuit::ProgramWithDependencies::new( + lee::privacy_preserving_transaction::circuit::ProgramWithDependencies::new( vault_program, HashMap::from([( Program::authenticated_transfer_program().id(), @@ -309,7 +309,7 @@ async fn claim_funds_from_vault_to_private( .await .context("Failed to confirm private vault claim transaction")?; - let NSSATransaction::PrivacyPreserving(tx) = transfer_tx else { + let LeeTransaction::PrivacyPreserving(tx) = transfer_tx else { bail!("Expected privacy preserving transaction result for private vault claim"); }; diff --git a/test_program_methods/guest/Cargo.toml b/test_program_methods/guest/Cargo.toml index 47ea10e1..f08b520b 100644 --- a/test_program_methods/guest/Cargo.toml +++ b/test_program_methods/guest/Cargo.toml @@ -8,7 +8,7 @@ license = { workspace = true } workspace = true [dependencies] -nssa_core.workspace = true +lee_core.workspace = true authenticated_transfer_core.workspace = true clock_core.workspace = true faucet_core.workspace = true diff --git a/test_program_methods/guest/src/bin/auth_asserting_noop.rs b/test_program_methods/guest/src/bin/auth_asserting_noop.rs index 0b6d9176..91983c1d 100644 --- a/test_program_methods/guest/src/bin/auth_asserting_noop.rs +++ b/test_program_methods/guest/src/bin/auth_asserting_noop.rs @@ -1,4 +1,4 @@ -use nssa_core::program::{AccountPostState, ProgramInput, ProgramOutput, read_nssa_inputs}; +use lee_core::program::{AccountPostState, ProgramInput, ProgramOutput, read_lee_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 @@ -15,7 +15,7 @@ fn main() { .. }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); for pre in &pre_states { assert!( diff --git a/test_program_methods/guest/src/bin/auth_transfer_proxy.rs b/test_program_methods/guest/src/bin/auth_transfer_proxy.rs index b3590074..a7e2f5be 100644 --- a/test_program_methods/guest/src/bin/auth_transfer_proxy.rs +++ b/test_program_methods/guest/src/bin/auth_transfer_proxy.rs @@ -1,6 +1,5 @@ -use nssa_core::program::{ - AccountPostState, ChainedCall, PdaSeed, ProgramId, ProgramInput, ProgramOutput, - read_nssa_inputs, +use lee_core::program::{ + AccountPostState, ChainedCall, PdaSeed, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, }; /// PDA authorization program that delegates balance operations to `authenticated_transfer`. @@ -39,7 +38,7 @@ fn main() { instruction: (pda_seed, auth_transfer_id, amount, is_withdraw), }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); if is_withdraw { let Ok([pda_pre, recipient_pre]) = <[_; 2]>::try_from(pre_states.clone()) else { diff --git a/test_program_methods/guest/src/bin/burner.rs b/test_program_methods/guest/src/bin/burner.rs index 02be2d38..4cbf61a2 100644 --- a/test_program_methods/guest/src/bin/burner.rs +++ b/test_program_methods/guest/src/bin/burner.rs @@ -1,4 +1,4 @@ -use nssa_core::program::{AccountPostState, ProgramInput, ProgramOutput, read_nssa_inputs}; +use lee_core::program::{AccountPostState, ProgramInput, ProgramOutput, read_lee_inputs}; type Instruction = u128; @@ -11,7 +11,7 @@ fn main() { instruction: balance_to_burn, }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let Ok([pre]) = <[_; 1]>::try_from(pre_states) else { return; diff --git a/test_program_methods/guest/src/bin/chain_caller.rs b/test_program_methods/guest/src/bin/chain_caller.rs index ac25301b..0473f1d2 100644 --- a/test_program_methods/guest/src/bin/chain_caller.rs +++ b/test_program_methods/guest/src/bin/chain_caller.rs @@ -1,7 +1,6 @@ use authenticated_transfer_core::Instruction as AuthTransferInstruction; -use nssa_core::program::{ - AccountPostState, ChainedCall, PdaSeed, ProgramId, ProgramInput, ProgramOutput, - read_nssa_inputs, +use lee_core::program::{ + AccountPostState, ChainedCall, PdaSeed, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, }; use risc0_zkvm::serde::to_vec; @@ -20,7 +19,7 @@ fn main() { instruction: (balance, auth_transfer_id, num_chain_calls, pda_seed), }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let Ok([recipient_pre, sender_pre]) = <[_; 2]>::try_from(pre_states) else { return; diff --git a/test_program_methods/guest/src/bin/changer_claimer.rs b/test_program_methods/guest/src/bin/changer_claimer.rs index 6d2b51b4..0d3c0df8 100644 --- a/test_program_methods/guest/src/bin/changer_claimer.rs +++ b/test_program_methods/guest/src/bin/changer_claimer.rs @@ -1,4 +1,4 @@ -use nssa_core::program::{AccountPostState, Claim, ProgramInput, ProgramOutput, read_nssa_inputs}; +use lee_core::program::{AccountPostState, Claim, ProgramInput, ProgramOutput, read_lee_inputs}; type Instruction = (Option>, bool); @@ -12,7 +12,7 @@ fn main() { instruction: (data_opt, should_claim), }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let Ok([pre]) = <[_; 1]>::try_from(pre_states) else { return; diff --git a/test_program_methods/guest/src/bin/claimer.rs b/test_program_methods/guest/src/bin/claimer.rs index a3a7fb19..b0efe992 100644 --- a/test_program_methods/guest/src/bin/claimer.rs +++ b/test_program_methods/guest/src/bin/claimer.rs @@ -1,4 +1,4 @@ -use nssa_core::program::{AccountPostState, Claim, ProgramInput, ProgramOutput, read_nssa_inputs}; +use lee_core::program::{AccountPostState, Claim, ProgramInput, ProgramOutput, read_lee_inputs}; type Instruction = (); @@ -11,7 +11,7 @@ fn main() { instruction: (), }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let Ok([pre]) = <[_; 1]>::try_from(pre_states) else { return; diff --git a/test_program_methods/guest/src/bin/clock_chain_caller.rs b/test_program_methods/guest/src/bin/clock_chain_caller.rs index cdbe5214..fc9b81c3 100644 --- a/test_program_methods/guest/src/bin/clock_chain_caller.rs +++ b/test_program_methods/guest/src/bin/clock_chain_caller.rs @@ -1,7 +1,7 @@ -use nssa_core::{ +use lee_core::{ Timestamp, program::{ - AccountPostState, ChainedCall, ProgramId, ProgramInput, ProgramOutput, read_nssa_inputs, + AccountPostState, ChainedCall, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, }, }; use risc0_zkvm::serde::to_vec; @@ -20,7 +20,7 @@ fn main() { instruction: (clock_program_id, timestamp), }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let post_states: Vec<_> = pre_states .iter() diff --git a/test_program_methods/guest/src/bin/data_changer.rs b/test_program_methods/guest/src/bin/data_changer.rs index 3969d7f6..4ab30a61 100644 --- a/test_program_methods/guest/src/bin/data_changer.rs +++ b/test_program_methods/guest/src/bin/data_changer.rs @@ -1,4 +1,4 @@ -use nssa_core::program::{AccountPostState, Claim, ProgramInput, ProgramOutput, read_nssa_inputs}; +use lee_core::program::{AccountPostState, Claim, ProgramInput, ProgramOutput, read_lee_inputs}; type Instruction = Vec; @@ -12,7 +12,7 @@ fn main() { instruction: data, }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let Ok([pre]) = <[_; 1]>::try_from(pre_states) else { return; diff --git a/test_program_methods/guest/src/bin/extra_output.rs b/test_program_methods/guest/src/bin/extra_output.rs index 3a5df556..6c9ee9ed 100644 --- a/test_program_methods/guest/src/bin/extra_output.rs +++ b/test_program_methods/guest/src/bin/extra_output.rs @@ -1,6 +1,6 @@ -use nssa_core::{ +use lee_core::{ account::Account, - program::{AccountPostState, ProgramInput, ProgramOutput, read_nssa_inputs}, + program::{AccountPostState, ProgramInput, ProgramOutput, read_lee_inputs}, }; type Instruction = (); @@ -14,7 +14,7 @@ fn main() { .. }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let Ok([pre]) = <[_; 1]>::try_from(pre_states) else { return; diff --git a/test_program_methods/guest/src/bin/faucet_chain_caller.rs b/test_program_methods/guest/src/bin/faucet_chain_caller.rs index 2e02982d..0b320a75 100644 --- a/test_program_methods/guest/src/bin/faucet_chain_caller.rs +++ b/test_program_methods/guest/src/bin/faucet_chain_caller.rs @@ -1,7 +1,7 @@ -use nssa_core::{ +use lee_core::{ account::AccountId, program::{ - AccountPostState, ChainedCall, ProgramId, ProgramInput, ProgramOutput, read_nssa_inputs, + AccountPostState, ChainedCall, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, }, }; use risc0_zkvm::serde::to_vec; @@ -18,7 +18,7 @@ fn main() { instruction: (faucet_program_id, vault_program_id, recipient_id, amount), }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let post_states: Vec<_> = pre_states .iter() @@ -30,7 +30,7 @@ fn main() { let chained_calls = vec![ChainedCall { program_id: faucet_program_id, - instruction_data: to_vec(&faucet_core::Instruction::Transfer { + instruction_data: to_vec(&faucet_core::Instruction::GenesisTransferVault { vault_program_id, recipient_id, amount, diff --git a/test_program_methods/guest/src/bin/flash_swap_callback.rs b/test_program_methods/guest/src/bin/flash_swap_callback.rs index ca596163..5e1a30aa 100644 --- a/test_program_methods/guest/src/bin/flash_swap_callback.rs +++ b/test_program_methods/guest/src/bin/flash_swap_callback.rs @@ -24,9 +24,8 @@ //! called by any program. In production, a callback would typically verify the caller //! if it needs to trust the context it is called from. -use nssa_core::program::{ - AccountPostState, ChainedCall, PdaSeed, ProgramId, ProgramInput, ProgramOutput, - read_nssa_inputs, +use lee_core::program::{ + AccountPostState, ChainedCall, PdaSeed, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, }; use serde::{Deserialize, Serialize}; @@ -48,7 +47,7 @@ fn main() { instruction, }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); // pre_states[0] = vault (after transfer out), pre_states[1] = receiver (after transfer out) let Ok([vault_pre, receiver_pre]) = <[_; 2]>::try_from(pre_states) else { diff --git a/test_program_methods/guest/src/bin/flash_swap_initiator.rs b/test_program_methods/guest/src/bin/flash_swap_initiator.rs index c6a76ebd..15706c1e 100644 --- a/test_program_methods/guest/src/bin/flash_swap_initiator.rs +++ b/test_program_methods/guest/src/bin/flash_swap_initiator.rs @@ -31,15 +31,14 @@ //! //! # Tests //! -//! See `nssa/src/state.rs` for integration tests: +//! See `lee/src/state.rs` for integration tests: //! - `flash_swap_successful`: full round-trip, funds returned, state unchanged //! - `flash_swap_callback_keeps_funds_rollback`: callback keeps funds, full rollback //! - `flash_swap_self_call_targets_correct_program`: zero-amount self-call isolation test //! - `flash_swap_standalone_invariant_check_rejected`: `caller_program_id` access control -use nssa_core::program::{ - AccountPostState, ChainedCall, PdaSeed, ProgramId, ProgramInput, ProgramOutput, - read_nssa_inputs, +use lee_core::program::{ + AccountPostState, ChainedCall, PdaSeed, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, }; use serde::{Deserialize, Serialize}; @@ -78,7 +77,7 @@ fn main() { instruction, }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); match instruction { FlashSwapInstruction::Initiate { diff --git a/test_program_methods/guest/src/bin/malicious_authorization_changer.rs b/test_program_methods/guest/src/bin/malicious_authorization_changer.rs index 894f22bf..f1e3be6b 100644 --- a/test_program_methods/guest/src/bin/malicious_authorization_changer.rs +++ b/test_program_methods/guest/src/bin/malicious_authorization_changer.rs @@ -1,7 +1,7 @@ -use nssa_core::{ +use lee_core::{ account::AccountWithMetadata, program::{ - AccountPostState, ChainedCall, ProgramId, ProgramInput, ProgramOutput, read_nssa_inputs, + AccountPostState, ChainedCall, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, }, }; use risc0_zkvm::serde::to_vec; @@ -20,7 +20,7 @@ fn main() { instruction: (balance, transfer_program_id), }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let Ok([sender, receiver]) = <[_; 2]>::try_from(pre_states) else { return; diff --git a/test_program_methods/guest/src/bin/malicious_caller_program_id.rs b/test_program_methods/guest/src/bin/malicious_caller_program_id.rs index 2326190e..171ad693 100644 --- a/test_program_methods/guest/src/bin/malicious_caller_program_id.rs +++ b/test_program_methods/guest/src/bin/malicious_caller_program_id.rs @@ -1,5 +1,5 @@ -use nssa_core::program::{ - AccountPostState, DEFAULT_PROGRAM_ID, ProgramInput, ProgramOutput, read_nssa_inputs, +use lee_core::program::{ + AccountPostState, DEFAULT_PROGRAM_ID, ProgramInput, ProgramOutput, read_lee_inputs, }; type Instruction = (); @@ -13,7 +13,7 @@ fn main() { instruction: (), }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let post_states = pre_states .iter() diff --git a/test_program_methods/guest/src/bin/malicious_injector.rs b/test_program_methods/guest/src/bin/malicious_injector.rs index 4e7300a2..f02e876c 100644 --- a/test_program_methods/guest/src/bin/malicious_injector.rs +++ b/test_program_methods/guest/src/bin/malicious_injector.rs @@ -1,7 +1,7 @@ -use nssa_core::{ +use lee_core::{ account::{Account, AccountId, AccountWithMetadata, Data, Nonce}, program::{ - AccountPostState, ChainedCall, ProgramId, ProgramInput, ProgramOutput, read_nssa_inputs, + AccountPostState, ChainedCall, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, }, }; @@ -48,7 +48,7 @@ fn main() { ), }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); // Echo own pre_states (attacker's account) unchanged. let post_states = pre_states diff --git a/test_program_methods/guest/src/bin/malicious_launderer.rs b/test_program_methods/guest/src/bin/malicious_launderer.rs index 6d0568fd..6794f0c0 100644 --- a/test_program_methods/guest/src/bin/malicious_launderer.rs +++ b/test_program_methods/guest/src/bin/malicious_launderer.rs @@ -1,4 +1,4 @@ -use nssa_core::program::{ChainedCall, ProgramId, ProgramInput, ProgramOutput, read_nssa_inputs}; +use lee_core::program::{ChainedCall, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs}; /// Instruction: (`auth_transfer_id`, `amount`) — both primitive, safe for `risc0_zkvm::serde`. type Instruction = (ProgramId, u128); @@ -12,7 +12,7 @@ fn main() { instruction: (auth_transfer_id, amount), }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); // Output empty pre/post states. P2 processes no accounts itself, so the // authorization check at validated_state_diff.rs:158-182 runs over nothing. diff --git a/test_program_methods/guest/src/bin/malicious_self_program_id.rs b/test_program_methods/guest/src/bin/malicious_self_program_id.rs index be447ab9..da719514 100644 --- a/test_program_methods/guest/src/bin/malicious_self_program_id.rs +++ b/test_program_methods/guest/src/bin/malicious_self_program_id.rs @@ -1,5 +1,5 @@ -use nssa_core::program::{ - AccountPostState, DEFAULT_PROGRAM_ID, ProgramInput, ProgramOutput, read_nssa_inputs, +use lee_core::program::{ + AccountPostState, DEFAULT_PROGRAM_ID, ProgramInput, ProgramOutput, read_lee_inputs, }; type Instruction = (); @@ -13,7 +13,7 @@ fn main() { instruction: (), }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let post_states = pre_states .iter() diff --git a/test_program_methods/guest/src/bin/minter.rs b/test_program_methods/guest/src/bin/minter.rs index 1f31ca05..a71c3200 100644 --- a/test_program_methods/guest/src/bin/minter.rs +++ b/test_program_methods/guest/src/bin/minter.rs @@ -1,4 +1,4 @@ -use nssa_core::program::{AccountPostState, ProgramInput, ProgramOutput, read_nssa_inputs}; +use lee_core::program::{AccountPostState, ProgramInput, ProgramOutput, read_lee_inputs}; type Instruction = (); @@ -11,7 +11,7 @@ fn main() { .. }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let Ok([pre]) = <[_; 1]>::try_from(pre_states) else { return; diff --git a/test_program_methods/guest/src/bin/missing_output.rs b/test_program_methods/guest/src/bin/missing_output.rs index d7d2778d..e8c53a34 100644 --- a/test_program_methods/guest/src/bin/missing_output.rs +++ b/test_program_methods/guest/src/bin/missing_output.rs @@ -1,4 +1,4 @@ -use nssa_core::program::{AccountPostState, ProgramInput, ProgramOutput, read_nssa_inputs}; +use lee_core::program::{AccountPostState, ProgramInput, ProgramOutput, read_lee_inputs}; type Instruction = (); @@ -11,7 +11,7 @@ fn main() { .. }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let Ok([pre1, pre2]) = <[_; 2]>::try_from(pre_states) else { return; diff --git a/test_program_methods/guest/src/bin/modified_transfer.rs b/test_program_methods/guest/src/bin/modified_transfer.rs index 2c05921c..c3fe096a 100644 --- a/test_program_methods/guest/src/bin/modified_transfer.rs +++ b/test_program_methods/guest/src/bin/modified_transfer.rs @@ -3,9 +3,9 @@ reason = "This program is intentionally malicious and is expected to have side effects." )] -use nssa_core::{ +use lee_core::{ account::{Account, AccountWithMetadata}, - program::{AccountPostState, ProgramInput, ProgramOutput, read_nssa_inputs}, + program::{AccountPostState, ProgramInput, ProgramOutput, read_lee_inputs}, }; /// Initializes a default account under the ownership of this program. @@ -70,7 +70,7 @@ fn main() { instruction: balance_to_move, }, instruction_data, - ) = read_nssa_inputs(); + ) = read_lee_inputs(); let post_states = match (pre_states.as_slice(), balance_to_move) { ([account_to_claim], 0) => { diff --git a/test_program_methods/guest/src/bin/nonce_changer.rs b/test_program_methods/guest/src/bin/nonce_changer.rs index c6e851fe..9b00fc83 100644 --- a/test_program_methods/guest/src/bin/nonce_changer.rs +++ b/test_program_methods/guest/src/bin/nonce_changer.rs @@ -1,4 +1,4 @@ -use nssa_core::program::{AccountPostState, ProgramInput, ProgramOutput, read_nssa_inputs}; +use lee_core::program::{AccountPostState, ProgramInput, ProgramOutput, read_lee_inputs}; type Instruction = (); @@ -11,7 +11,7 @@ fn main() { .. }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let Ok([pre]) = <[_; 1]>::try_from(pre_states) else { return; diff --git a/test_program_methods/guest/src/bin/noop.rs b/test_program_methods/guest/src/bin/noop.rs index fc92aebe..09bd1cca 100644 --- a/test_program_methods/guest/src/bin/noop.rs +++ b/test_program_methods/guest/src/bin/noop.rs @@ -1,4 +1,4 @@ -use nssa_core::program::{AccountPostState, ProgramInput, ProgramOutput, read_nssa_inputs}; +use lee_core::program::{AccountPostState, ProgramInput, ProgramOutput, read_lee_inputs}; type Instruction = (); @@ -11,7 +11,7 @@ fn main() { .. }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let post_states = pre_states .iter() diff --git a/test_program_methods/guest/src/bin/pda_claimer.rs b/test_program_methods/guest/src/bin/pda_claimer.rs index 5dec4da4..2571aadf 100644 --- a/test_program_methods/guest/src/bin/pda_claimer.rs +++ b/test_program_methods/guest/src/bin/pda_claimer.rs @@ -1,5 +1,5 @@ -use nssa_core::program::{ - AccountPostState, Claim, PdaSeed, ProgramInput, ProgramOutput, read_nssa_inputs, +use lee_core::program::{ + AccountPostState, Claim, PdaSeed, ProgramInput, ProgramOutput, read_lee_inputs, }; type Instruction = PdaSeed; @@ -13,7 +13,7 @@ fn main() { instruction: seed, }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let Ok([pre]) = <[_; 1]>::try_from(pre_states) else { return; diff --git a/test_program_methods/guest/src/bin/pda_spend_proxy.rs b/test_program_methods/guest/src/bin/pda_spend_proxy.rs index 4094e101..5b00004c 100644 --- a/test_program_methods/guest/src/bin/pda_spend_proxy.rs +++ b/test_program_methods/guest/src/bin/pda_spend_proxy.rs @@ -1,6 +1,5 @@ -use nssa_core::program::{ - AccountPostState, ChainedCall, PdaSeed, ProgramId, ProgramInput, ProgramOutput, - read_nssa_inputs, +use lee_core::program::{ + AccountPostState, ChainedCall, PdaSeed, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, }; use risc0_zkvm::serde::to_vec; @@ -19,7 +18,7 @@ fn main() { instruction: (seed, amount, auth_transfer_id), }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let Ok([first, second]) = <[_; 2]>::try_from(pre_states) else { return; diff --git a/test_program_methods/guest/src/bin/pinata_cooldown.rs b/test_program_methods/guest/src/bin/pinata_cooldown.rs index 9e8bde3b..160fba21 100644 --- a/test_program_methods/guest/src/bin/pinata_cooldown.rs +++ b/test_program_methods/guest/src/bin/pinata_cooldown.rs @@ -13,7 +13,7 @@ //! [prize: u64 LE | `cooldown_ms`: u64 LE | `last_claim_timestamp`: u64 LE]. use clock_core::{CLOCK_01_PROGRAM_ACCOUNT_ID, ClockAccountData}; -use nssa_core::program::{AccountPostState, Claim, ProgramInput, ProgramOutput, read_nssa_inputs}; +use lee_core::program::{AccountPostState, Claim, ProgramInput, ProgramOutput, read_lee_inputs}; type Instruction = (); @@ -54,7 +54,7 @@ fn main() { instruction: (), }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let Ok([pinata, winner, clock_pre]) = <[_; 3]>::try_from(pre_states) else { panic!("Expected exactly 3 input accounts: pinata, winner, clock"); diff --git a/test_program_methods/guest/src/bin/private_pda_delegator.rs b/test_program_methods/guest/src/bin/private_pda_delegator.rs index fe55045e..766465e3 100644 --- a/test_program_methods/guest/src/bin/private_pda_delegator.rs +++ b/test_program_methods/guest/src/bin/private_pda_delegator.rs @@ -1,6 +1,6 @@ -use nssa_core::program::{ +use lee_core::program::{ AccountPostState, ChainedCall, Claim, PdaSeed, ProgramId, ProgramInput, ProgramOutput, - read_nssa_inputs, + read_lee_inputs, }; use risc0_zkvm::serde::to_vec; @@ -20,7 +20,7 @@ fn main() { instruction: (claim_seed, delegated_seed, callee_program_id), }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let Ok([pre]) = <[_; 1]>::try_from(pre_states) else { return; diff --git a/test_program_methods/guest/src/bin/program_owner_changer.rs b/test_program_methods/guest/src/bin/program_owner_changer.rs index 0282b5cc..ef2c5990 100644 --- a/test_program_methods/guest/src/bin/program_owner_changer.rs +++ b/test_program_methods/guest/src/bin/program_owner_changer.rs @@ -1,4 +1,4 @@ -use nssa_core::program::{AccountPostState, ProgramInput, ProgramOutput, read_nssa_inputs}; +use lee_core::program::{AccountPostState, ProgramInput, ProgramOutput, read_lee_inputs}; type Instruction = (); @@ -11,7 +11,7 @@ fn main() { .. }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let Ok([pre]) = <[_; 1]>::try_from(pre_states) else { return; diff --git a/test_program_methods/guest/src/bin/simple_balance_transfer.rs b/test_program_methods/guest/src/bin/simple_balance_transfer.rs index f324b371..29149272 100644 --- a/test_program_methods/guest/src/bin/simple_balance_transfer.rs +++ b/test_program_methods/guest/src/bin/simple_balance_transfer.rs @@ -1,4 +1,4 @@ -use nssa_core::program::{AccountPostState, ProgramInput, ProgramOutput, read_nssa_inputs}; +use lee_core::program::{AccountPostState, ProgramInput, ProgramOutput, read_lee_inputs}; type Instruction = u128; @@ -11,7 +11,7 @@ fn main() { instruction: balance, }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let Ok([sender_pre, receiver_pre]) = <[_; 2]>::try_from(pre_states) else { return; diff --git a/test_program_methods/guest/src/bin/time_locked_transfer.rs b/test_program_methods/guest/src/bin/time_locked_transfer.rs index 25595661..8746ef84 100644 --- a/test_program_methods/guest/src/bin/time_locked_transfer.rs +++ b/test_program_methods/guest/src/bin/time_locked_transfer.rs @@ -10,7 +10,7 @@ //! 2 - clock account (read-only, e.g. `CLOCK_01`). use clock_core::{CLOCK_01_PROGRAM_ACCOUNT_ID, ClockAccountData}; -use nssa_core::program::{AccountPostState, ProgramInput, ProgramOutput, read_nssa_inputs}; +use lee_core::program::{AccountPostState, ProgramInput, ProgramOutput, read_lee_inputs}; /// (`amount`, `deadline_timestamp`). type Instruction = (u128, u64); @@ -24,7 +24,7 @@ fn main() { instruction: (amount, deadline), }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let Ok([sender_pre, receiver_pre, clock_pre]) = <[_; 3]>::try_from(pre_states) else { panic!("Expected exactly 3 input accounts: sender, receiver, clock"); diff --git a/test_program_methods/guest/src/bin/two_pda_claimer.rs b/test_program_methods/guest/src/bin/two_pda_claimer.rs index 53aae666..57df37d5 100644 --- a/test_program_methods/guest/src/bin/two_pda_claimer.rs +++ b/test_program_methods/guest/src/bin/two_pda_claimer.rs @@ -1,5 +1,5 @@ -use nssa_core::program::{ - AccountPostState, Claim, PdaSeed, ProgramInput, ProgramOutput, read_nssa_inputs, +use lee_core::program::{ + AccountPostState, Claim, PdaSeed, ProgramInput, ProgramOutput, read_lee_inputs, }; /// Claims two `pre_states` under the same `seed`. Used to exercise the tx-wide @@ -17,7 +17,7 @@ fn main() { instruction: seed, }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let Ok([pre_a, pre_b]) = <[_; 2]>::try_from(pre_states) else { return; diff --git a/test_program_methods/guest/src/bin/validity_window.rs b/test_program_methods/guest/src/bin/validity_window.rs index 03100e8e..ad7ecbb7 100644 --- a/test_program_methods/guest/src/bin/validity_window.rs +++ b/test_program_methods/guest/src/bin/validity_window.rs @@ -1,6 +1,6 @@ -use nssa_core::program::{ +use lee_core::program::{ AccountPostState, BlockValidityWindow, ProgramInput, ProgramOutput, TimestampValidityWindow, - read_nssa_inputs, + read_lee_inputs, }; type Instruction = (BlockValidityWindow, TimestampValidityWindow); @@ -14,7 +14,7 @@ fn main() { instruction: (block_validity_window, timestamp_validity_window), }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let Ok([pre]) = <[_; 1]>::try_from(pre_states) else { return; diff --git a/test_program_methods/guest/src/bin/validity_window_chain_caller.rs b/test_program_methods/guest/src/bin/validity_window_chain_caller.rs index 212418a2..91b2dead 100644 --- a/test_program_methods/guest/src/bin/validity_window_chain_caller.rs +++ b/test_program_methods/guest/src/bin/validity_window_chain_caller.rs @@ -1,6 +1,6 @@ -use nssa_core::program::{ +use lee_core::program::{ AccountPostState, BlockValidityWindow, ChainedCall, ProgramId, ProgramInput, ProgramOutput, - TimestampValidityWindow, read_nssa_inputs, + TimestampValidityWindow, read_lee_inputs, }; use risc0_zkvm::serde::to_vec; @@ -22,7 +22,7 @@ fn main() { instruction: (block_validity_window, chained_program_id, chained_block_validity_window), }, instruction_words, - ) = read_nssa_inputs::(); + ) = read_lee_inputs::(); let [pre] = <[_; 1]>::try_from(pre_states.clone()).expect("Expected exactly one pre state"); let post = pre.account.clone(); diff --git a/tools/crypto_primitives_bench/Cargo.toml b/tools/crypto_primitives_bench/Cargo.toml index 8e99f79f..780fac77 100644 --- a/tools/crypto_primitives_bench/Cargo.toml +++ b/tools/crypto_primitives_bench/Cargo.toml @@ -10,7 +10,7 @@ workspace = true [dev-dependencies] key_protocol.workspace = true -nssa_core = { workspace = true, features = ["host"] } +lee_core = { workspace = true, features = ["host"] } rand = { workspace = true } criterion.workspace = true diff --git a/tools/crypto_primitives_bench/benches/primitives.rs b/tools/crypto_primitives_bench/benches/primitives.rs index cfa0858f..11c11d9b 100644 --- a/tools/crypto_primitives_bench/benches/primitives.rs +++ b/tools/crypto_primitives_bench/benches/primitives.rs @@ -3,20 +3,18 @@ //! Measures: //! - `KeyChain::new_os_random` (mnemonic → SSK → NSK/VSK + public keys) //! - `KeyChain::new_mnemonic` (same, but mnemonic exposed) -//! - `SharedSecretKey::new` (Diffie-Hellman shared key derivation, the per-recipient cost) +//! - `SharedSecretKey::encapsulate` (ML-KEM-768 encapsulation, the per-recipient cost) //! - `EncryptionScheme::encrypt` / `decrypt` (Account note encryption) use std::time::Duration; use criterion::{Criterion, criterion_group, criterion_main}; use key_protocol::key_management::KeyChain; -use nssa_core::{ +use lee_core::{ Commitment, EncryptionScheme, SharedSecretKey, account::{Account, AccountId}, - encryption::{EphemeralPublicKey, EphemeralSecretKey}, program::PrivateAccountKind, }; -use rand::{RngCore as _, rngs::OsRng}; fn bench_keychain(c: &mut Criterion) { let mut g = c.benchmark_group("keychain"); @@ -37,34 +35,22 @@ fn bench_shared_secret_key(c: &mut Criterion) { let mut g = c.benchmark_group("shared_secret_key"); g.sample_size(50).noise_threshold(0.05); - g.bench_function("sender_dh", |b| { - b.iter(|| { - let mut bytes = [0_u8; 32]; - OsRng.fill_bytes(&mut bytes); - let esk: EphemeralSecretKey = bytes; - let _epk = EphemeralPublicKey::from(&esk); - SharedSecretKey::new(esk, &vpk) - }); + g.bench_function("sender_encapsulate", |b| { + b.iter(|| SharedSecretKey::encapsulate(&vpk)); }); g.finish(); } fn bench_encryption(c: &mut Criterion) { // One-time setup: a fixed Account/Commitment and a SharedSecretKey to bench - // encrypt/decrypt over a representative note. ESK gen is excluded from the - // measured loop (covered by the SharedSecretKey bench above). + // encrypt/decrypt over a representative note. Encapsulation cost is covered + // by the SharedSecretKey bench above. let recipient_kc = KeyChain::new_os_random(); - let vpk = recipient_kc.viewing_public_key; let npk = recipient_kc.nullifier_public_key; let account = Account::default(); let account_id = AccountId::for_regular_private_account(&npk, 0); let commitment = Commitment::new(&account_id, &account); - let shared = { - let mut bytes = [0_u8; 32]; - OsRng.fill_bytes(&mut bytes); - let esk: EphemeralSecretKey = bytes; - SharedSecretKey::new(esk, &vpk) - }; + let (shared, _epk) = SharedSecretKey::encapsulate(&recipient_kc.viewing_public_key); let kind = PrivateAccountKind::Regular(0_u128); let output_index: u32 = 0; @@ -73,7 +59,6 @@ fn bench_encryption(c: &mut Criterion) { g.bench_function("encrypt", |b| { b.iter(|| EncryptionScheme::encrypt(&account, &kind, &shared, &commitment, output_index)); }); - // One ciphertext for the decrypt bench (encrypt is deterministic given inputs). let ct = EncryptionScheme::encrypt(&account, &kind, &shared, &commitment, output_index); g.bench_function("decrypt", |b| { b.iter(|| EncryptionScheme::decrypt(&ct, &shared, &commitment, output_index)); diff --git a/tools/cycle_bench/Cargo.toml b/tools/cycle_bench/Cargo.toml index 13ea0023..03491c98 100644 --- a/tools/cycle_bench/Cargo.toml +++ b/tools/cycle_bench/Cargo.toml @@ -10,12 +10,12 @@ workspace = true [features] default = [] -prove = ["nssa/prove", "risc0-zkvm/prove"] +prove = ["lee/prove", "risc0-zkvm/prove"] ppe = ["prove"] [dependencies] -nssa = { workspace = true } -nssa_core = { workspace = true, features = ["host"] } +lee = { workspace = true } +lee_core = { workspace = true, features = ["host"] } authenticated_transfer_core.workspace = true clock_core.workspace = true token_core.workspace = true diff --git a/tools/cycle_bench/benches/verify.rs b/tools/cycle_bench/benches/verify.rs index d7bdfbe3..648262f1 100644 --- a/tools/cycle_bench/benches/verify.rs +++ b/tools/cycle_bench/benches/verify.rs @@ -11,7 +11,7 @@ use std::{hint::black_box, time::Duration}; use anyhow::Context as _; use criterion::{Criterion, criterion_group, criterion_main}; use cycle_bench::ppe::prove_auth_transfer_in_ppe; -use nssa::program_methods::PRIVACY_PRESERVING_CIRCUIT_ID; +use lee::program_methods::PRIVACY_PRESERVING_CIRCUIT_ID; use risc0_zkvm::{InnerReceipt, Receipt}; fn bench_verify(c: &mut Criterion) { diff --git a/tools/cycle_bench/src/main.rs b/tools/cycle_bench/src/main.rs index bb44fb4f..914d68c5 100644 --- a/tools/cycle_bench/src/main.rs +++ b/tools/cycle_bench/src/main.rs @@ -28,12 +28,12 @@ use clock_core::{ ClockAccountData, }; use cycle_bench::{ppe, stats::Stats}; -use nssa::program_methods::{ +use lee::program_methods::{ AMM_ELF, AMM_ID, ASSOCIATED_TOKEN_ACCOUNT_ELF, ASSOCIATED_TOKEN_ACCOUNT_ID, AUTHENTICATED_TRANSFER_ELF, AUTHENTICATED_TRANSFER_ID, CLOCK_ELF, CLOCK_ID, TOKEN_ELF, TOKEN_ID, }; -use nssa_core::{ +use lee_core::{ Timestamp, account::{Account, AccountId, AccountWithMetadata, Data}, program::{InstructionData, ProgramId}, diff --git a/tools/cycle_bench/src/ppe/ppe_impl.rs b/tools/cycle_bench/src/ppe/ppe_impl.rs index 433c4aa4..4d47bebc 100644 --- a/tools/cycle_bench/src/ppe/ppe_impl.rs +++ b/tools/cycle_bench/src/ppe/ppe_impl.rs @@ -5,12 +5,12 @@ use std::{collections::HashMap, time::Instant}; -use nssa::{ +use lee::{ execute_and_prove, privacy_preserving_transaction::circuit::{ProgramWithDependencies, Proof}, program::Program, }; -use nssa_core::{ +use lee_core::{ InputAccountIdentity, PrivacyPreservingCircuitOutput, account::{Account, AccountId, AccountWithMetadata}, program::ProgramId, @@ -19,8 +19,8 @@ use risc0_zkvm::serde::to_vec; use super::PpeBenchResult; -const AUTH_TRANSFER_ID: ProgramId = nssa::program_methods::AUTHENTICATED_TRANSFER_ID; -const AUTH_TRANSFER_ELF: &[u8] = nssa::program_methods::AUTHENTICATED_TRANSFER_ELF; +const AUTH_TRANSFER_ID: ProgramId = lee::program_methods::AUTHENTICATED_TRANSFER_ID; +const AUTH_TRANSFER_ELF: &[u8] = lee::program_methods::AUTHENTICATED_TRANSFER_ELF; /// `chain_caller` bytecode shipped at `artifacts/test_program_methods/chain_caller.bin`. /// Loaded at compile time so we don't need a dev-dependency on `test_program_methods`. @@ -144,7 +144,7 @@ fn prove_chain_caller( let pre_states = vec![recipient_pre, sender_pre]; let balance: u128 = 1; - let pda_seed: Option = None; + let pda_seed: Option = None; let instruction = (balance, AUTH_TRANSFER_ID, num_chain_calls, pda_seed); let instruction_data = to_vec(&instruction)?; diff --git a/tools/integration_bench/Cargo.toml b/tools/integration_bench/Cargo.toml index 0829a7f0..0d8419f1 100644 --- a/tools/integration_bench/Cargo.toml +++ b/tools/integration_bench/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] common.workspace = true indexer_service_rpc = { workspace = true, features = ["client"] } -nssa.workspace = true +lee.workspace = true sequencer_service_rpc = { workspace = true, features = ["client"] } test_fixtures.workspace = true wallet.workspace = true diff --git a/tools/integration_bench/src/harness.rs b/tools/integration_bench/src/harness.rs index 813bbbab..369387e3 100644 --- a/tools/integration_bench/src/harness.rs +++ b/tools/integration_bench/src/harness.rs @@ -8,7 +8,7 @@ use std::time::{Duration, Instant}; use anyhow::{Result, bail}; -use common::transaction::NSSATransaction; +use common::transaction::LeeTransaction; use sequencer_service_rpc::RpcClient as _; use serde::{Serialize, Serializer}; use test_fixtures::{DiskSizes, TestContext}; @@ -161,9 +161,9 @@ async fn finalize_step( for tx in &block.body.transactions { let n = borsh::to_vec(tx).map_or(0, |v| v.len()); match tx { - NSSATransaction::Public(_) => sz.public_tx_bytes.push(n), - NSSATransaction::PrivacyPreserving(_) => sz.ppe_tx_bytes.push(n), - NSSATransaction::ProgramDeployment(_) => sz.deploy_tx_bytes.push(n), + LeeTransaction::Public(_) => sz.public_tx_bytes.push(n), + LeeTransaction::PrivacyPreserving(_) => sz.ppe_tx_bytes.push(n), + LeeTransaction::ProgramDeployment(_) => sz.deploy_tx_bytes.push(n), } } blocks.push(sz); diff --git a/tools/integration_bench/src/scenarios/amm.rs b/tools/integration_bench/src/scenarios/amm.rs index 79100c42..483010eb 100644 --- a/tools/integration_bench/src/scenarios/amm.rs +++ b/tools/integration_bench/src/scenarios/amm.rs @@ -118,7 +118,7 @@ async fn new_public_account( ctx: &mut TestContext, output: &mut ScenarioOutput, label: &str, -) -> Result { +) -> Result { let ret = output .step(ctx, label, async |ctx| { wallet::cli::execute_subcommand( @@ -141,8 +141,8 @@ async fn timed_token_new( ctx: &mut TestContext, output: &mut ScenarioOutput, label: &str, - def_id: nssa::AccountId, - supply_id: nssa::AccountId, + def_id: lee::AccountId, + supply_id: lee::AccountId, name: &str, ) -> Result<()> { let name = name.to_owned(); @@ -167,8 +167,8 @@ async fn timed_token_send( ctx: &mut TestContext, output: &mut ScenarioOutput, label: &str, - from_id: nssa::AccountId, - to_id: nssa::AccountId, + from_id: lee::AccountId, + to_id: lee::AccountId, amount: u128, ) -> Result<()> { output @@ -180,6 +180,7 @@ async fn timed_token_send( to: Some(public_mention(to_id)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount, }), diff --git a/tools/integration_bench/src/scenarios/fanout.rs b/tools/integration_bench/src/scenarios/fanout.rs index d03adf83..d230523b 100644 --- a/tools/integration_bench/src/scenarios/fanout.rs +++ b/tools/integration_bench/src/scenarios/fanout.rs @@ -50,6 +50,7 @@ pub async fn run(ctx: &mut TestContext) -> Result { to: Some(public_mention(recipient_id)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: AMOUNT_PER_TRANSFER, }), @@ -66,7 +67,7 @@ async fn new_public_account( ctx: &mut TestContext, output: &mut ScenarioOutput, label: &str, -) -> Result { +) -> Result { let ret = output .step(ctx, label, async |ctx| { wallet::cli::execute_subcommand( diff --git a/tools/integration_bench/src/scenarios/parallel.rs b/tools/integration_bench/src/scenarios/parallel.rs index c6a265b9..3e69ad2b 100644 --- a/tools/integration_bench/src/scenarios/parallel.rs +++ b/tools/integration_bench/src/scenarios/parallel.rs @@ -6,7 +6,7 @@ use std::time::Instant; use anyhow::{Result, bail}; -use common::transaction::NSSATransaction; +use common::transaction::LeeTransaction; use sequencer_service_rpc::RpcClient as _; use test_fixtures::{TestContext, public_mention}; use wallet::cli::{ @@ -69,6 +69,7 @@ pub async fn run(ctx: &mut TestContext) -> Result { to: Some(public_mention(sender_id)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: AMOUNT_PER_TRANSFER * 5, }), @@ -97,6 +98,7 @@ pub async fn run(ctx: &mut TestContext) -> Result { to: Some(public_mention(*recipient_id)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: AMOUNT_PER_TRANSFER, }), @@ -139,9 +141,9 @@ pub async fn run(ctx: &mut TestContext) -> Result { for tx in &block.body.transactions { let n = borsh::to_vec(tx).map_or(0, |v| v.len()); match tx { - NSSATransaction::Public(_) => sz.public_tx_bytes.push(n), - NSSATransaction::PrivacyPreserving(_) => sz.ppe_tx_bytes.push(n), - NSSATransaction::ProgramDeployment(_) => sz.deploy_tx_bytes.push(n), + LeeTransaction::Public(_) => sz.public_tx_bytes.push(n), + LeeTransaction::PrivacyPreserving(_) => sz.ppe_tx_bytes.push(n), + LeeTransaction::ProgramDeployment(_) => sz.deploy_tx_bytes.push(n), } } blocks.push(sz); @@ -168,7 +170,7 @@ async fn new_public_account( ctx: &mut TestContext, output: &mut ScenarioOutput, label: &str, -) -> Result { +) -> Result { let ret = output .step(ctx, label, async |ctx| { wallet::cli::execute_subcommand( diff --git a/tools/integration_bench/src/scenarios/private.rs b/tools/integration_bench/src/scenarios/private.rs index 2be8c43c..be6bb33b 100644 --- a/tools/integration_bench/src/scenarios/private.rs +++ b/tools/integration_bench/src/scenarios/private.rs @@ -46,6 +46,7 @@ pub async fn run(ctx: &mut TestContext) -> Result { to: Some(private_mention(private_a)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: 1_000, }), @@ -64,6 +65,7 @@ pub async fn run(ctx: &mut TestContext) -> Result { to: Some(public_mention(public_recipient_id)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: 100, }), @@ -82,6 +84,7 @@ pub async fn run(ctx: &mut TestContext) -> Result { to: Some(private_mention(private_b)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: 200, }), @@ -97,7 +100,7 @@ async fn new_public_account( ctx: &mut TestContext, output: &mut ScenarioOutput, label: &str, -) -> Result { +) -> Result { let ret = output .step(ctx, label, async |ctx| { wallet::cli::execute_subcommand( @@ -120,7 +123,7 @@ async fn new_private_account( ctx: &mut TestContext, output: &mut ScenarioOutput, label: &str, -) -> Result { +) -> Result { let ret = output .step(ctx, label, async |ctx| { wallet::cli::execute_subcommand( diff --git a/tools/integration_bench/src/scenarios/token.rs b/tools/integration_bench/src/scenarios/token.rs index d1dfdef3..3cff19e9 100644 --- a/tools/integration_bench/src/scenarios/token.rs +++ b/tools/integration_bench/src/scenarios/token.rs @@ -41,6 +41,7 @@ pub async fn run(ctx: &mut TestContext) -> Result { to: Some(public_mention(recipient_id)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: 1_000, }), @@ -61,6 +62,7 @@ pub async fn run(ctx: &mut TestContext) -> Result { to: Some(private_mention(private_recipient_id)), to_npk: None, to_vpk: None, + to_keys: None, to_identifier: Some(0), amount: 500, }), @@ -76,7 +78,7 @@ async fn new_public_account( ctx: &mut TestContext, output: &mut ScenarioOutput, label: &str, -) -> Result { +) -> Result { let ret = output .step(ctx, label, async |ctx| { wallet::cli::execute_subcommand( @@ -99,7 +101,7 @@ async fn new_private_account( ctx: &mut TestContext, output: &mut ScenarioOutput, label: &str, -) -> Result { +) -> Result { let ret = output .step(ctx, label, async |ctx| { wallet::cli::execute_subcommand( diff --git a/wallet/src/program_facades/native_token_transfer/public.rs b/wallet/src/program_facades/native_token_transfer/public.rs deleted file mode 100644 index 66930fef..00000000 --- a/wallet/src/program_facades/native_token_transfer/public.rs +++ /dev/null @@ -1,41 +0,0 @@ -use authenticated_transfer_core::Instruction as AuthTransferInstruction; -use common::HashType; -use nssa::program::Program; - -use super::NativeTokenTransfer; -use crate::{ - AccountIdentity, ExecutionFailureKind, - program_facades::native_token_transfer::auth_transfer_preparation, -}; - -impl NativeTokenTransfer<'_> { - pub async fn send_public_transfer( - &self, - from: AccountIdentity, - to: AccountIdentity, - balance_to_move: u128, - ) -> Result { - let (instruction_data, program, tx_pre_check) = auth_transfer_preparation(balance_to_move); - - self.0 - .send_pub_tx_with_pre_check( - vec![from, to], - instruction_data, - &program.into(), - tx_pre_check, - ) - .await - } - - pub async fn register_account( - &self, - account: AccountIdentity, - ) -> Result { - let program = Program::authenticated_transfer_program(); - let instruction_data = Program::serialize_instruction(AuthTransferInstruction::Initialize)?; - - self.0 - .send_pub_tx(vec![account], instruction_data, &program.into()) - .await - } -}