From bbc8079391b9e59170748b62828418dc57fcbd9c Mon Sep 17 00:00:00 2001 From: Marvin Jones Date: Tue, 7 Jul 2026 15:53:38 -0400 Subject: [PATCH] test(privacy): add privacy-preserving test coverage for token and ata programs Validates the Q2 privacy features (shield/deshield, private-to-private transfers, existing-account crediting, group-owned accounts, and private PDAs) against the token and ata program flows, which previously ran almost entirely in public context. Adds the key_protocol dependency for GMS-based group-account tests and introduces a docs/privacy-test-matrix.md tracker mapping each program/instruction/ privacy-dimension combination to pass, fail, or not-expressible, with root-cause findings for each gap (notably that private PDAs are structurally unsupported by any program currently deriving addresses via for_public_pda). Co-Authored-By: Claude Sonnet 5 --- Cargo.lock | 3640 ++++++++++++++++++++- docs/privacy-test-matrix.md | 337 ++ programs/integration_tests/Cargo.toml | 1 + programs/integration_tests/tests/ata.rs | 540 ++- programs/integration_tests/tests/token.rs | 988 +++++- 5 files changed, 5477 insertions(+), 29 deletions(-) create mode 100644 docs/privacy-test-matrix.md diff --git a/Cargo.lock b/Cargo.lock index a4aec91..a606a84 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,47 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common 0.1.6", + "generic-array 0.14.9", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher 0.4.4", + "cpufeatures 0.2.17", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher 0.4.4", + "ctr", + "ghash", + "subtle", +] + [[package]] name = "ahash" version = "0.8.12" @@ -54,7 +95,7 @@ dependencies = [ "rustc-hash", "secp256k1", "serde", - "sha3", + "sha3 0.11.0", ] [[package]] @@ -116,6 +157,15 @@ version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" +[[package]] +name = "archery" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e0a5f99dfebb87bb342d0f53bb92c81842e100bbb915223e38349580e5441d" +dependencies = [ + "triomphe", +] + [[package]] name = "ark-bn254" version = "0.5.0" @@ -364,7 +414,7 @@ dependencies = [ "ark-ff 0.5.0", "ark-std 0.5.0", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.2.25", ] [[package]] @@ -460,12 +510,160 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236" +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + [[package]] name = "arrayvec" version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f02882884d3e1bc524fb12c79f107f6ad0e1cfd498c536ffb494301740995dfe" +[[package]] +name = "asn1-rs" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f43a50ac4fdca5df8e885c21b835997f0a1cdee65494a6847694a98652d9d8" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom 7.1.3", + "num-traits", + "rusticata-macros", + "thiserror 2.0.18", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", + "synstructure", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "asn1_der" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4858a9d740c5007a9069007c3b4e91152d0506f13c1b31dd49051fd537656156" + +[[package]] +name = "astro-float" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96034cc871c05bb65ad7fb77e6a8bebf45d8b055ed0311769e2f83a1d373c1ec" +dependencies = [ + "astro-float-macro", + "astro-float-num", +] + +[[package]] +name = "astro-float-macro" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05cfe0f6df5a74fb25b9e713470ad77e091f35f798730673c8772f26ed438963" +dependencies = [ + "astro-float-num", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "astro-float-num" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86887daca11d02e0b04f37a9cb81888aae881397fb48ff66494e356aea97554a" +dependencies = [ + "itertools 0.10.5", + "lazy_static", +] + +[[package]] +name = "async-channel" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-io" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" +dependencies = [ + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite", + "parking", + "polling", + "rustix", + "slab", + "windows-sys 0.61.2", +] + +[[package]] +name = "async-recursion" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "asynchronous-codec" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a860072022177f903e59730004fb5dc13db9275b79bb2aef7ba8ce831956c233" +dependencies = [ + "bytes", + "futures-sink", + "futures-util", + "memchr", + "pin-project-lite", +] + [[package]] name = "ata-methods" version = "0.1.0" @@ -500,6 +698,37 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "attohttpc" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d9a9bf8b79a749ee0b911b91b671cc2b6c670bdbc7e3dfd537576ddc94bb2a2" +dependencies = [ + "http 0.2.12", + "log", + "url", +] + +[[package]] +name = "attohttpc" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e2cdb6d5ed835199484bb92bb8b3edd526effe995c61732580439c1a67e2e9" +dependencies = [ + "base64", + "http 1.4.2", + "log", + "url", +] + +[[package]] +name = "authenticated_transfer_core" +version = "0.1.0" +source = "git+https://github.com/logos-blockchain/logos-execution-zone.git?tag=v0.2.0-rc6#e37876a64028a335eb693198a1ed6a0e875ec5b4" +dependencies = [ + "serde", +] + [[package]] name = "auto_impl" version = "1.3.0" @@ -517,12 +746,97 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" +[[package]] +name = "axum" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" +dependencies = [ + "async-trait", + "axum-core", + "bytes", + "futures-util", + "http 1.4.2", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 1.4.2", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper", + "tower-layer", + "tower-service", +] + +[[package]] +name = "backon" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cffb0e931875b666fc4fcb20fee52e9bbd1ef836fd9e9e04ec21555f9f85f7ef" +dependencies = [ + "fastrand", + "tokio", +] + +[[package]] +name = "base-x" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" + [[package]] name = "base16ct" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" +[[package]] +name = "base256emoji" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e9430d9a245a77c92176e649af6e275f20839a48389859d1661e9a128d077c" +dependencies = [ + "const-str", + "match-lookup", +] + +[[package]] +name = "base45" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240e56f4d3c453c36faacb695c535a4d5f8c7d23dac175014f32eb0a71012a03" + [[package]] name = "base58" version = "0.2.0" @@ -550,6 +864,17 @@ dependencies = [ "serde", ] +[[package]] +name = "bip39" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90dbd31c98227229239363921e60fcf5e558e43ec69094d46fc4996f08d1d5bc" +dependencies = [ + "bitcoin_hashes", + "serde", + "unicode-normalization", +] + [[package]] name = "bit-set" version = "0.8.0" @@ -647,7 +972,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array", + "generic-array 0.14.9", ] [[package]] @@ -696,6 +1021,15 @@ dependencies = [ "syn 2.0.118", ] +[[package]] +name = "bridge_core" +version = "0.1.0" +source = "git+https://github.com/logos-blockchain/logos-execution-zone.git?tag=v0.2.0-rc6#e37876a64028a335eb693198a1ed6a0e875ec5b4" +dependencies = [ + "lee_core", + "serde", +] + [[package]] name = "bs58" version = "0.5.1" @@ -831,10 +1165,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" dependencies = [ "cfg-if", - "cipher", + "cipher 0.5.2", "cpufeatures 0.3.0", ] +[[package]] +name = "chkstk_stub" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "047f6ab2f3b9bcaf23b593d1580898e4244d27eadf1a1fae99212ee5735d3d1c" +dependencies = [ + "cc", +] + [[package]] name = "chrono" version = "0.4.45" @@ -847,6 +1190,16 @@ dependencies = [ "windows-link", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common 0.1.6", + "inout 0.1.4", +] + [[package]] name = "cipher" version = "0.5.2" @@ -855,7 +1208,7 @@ checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c" dependencies = [ "block-buffer 0.12.1", "crypto-common 0.2.2", - "inout", + "inout 0.2.2", ] [[package]] @@ -882,6 +1235,38 @@ dependencies = [ "thiserror 2.0.18", ] +[[package]] +name = "common" +version = "0.1.0" +source = "git+https://github.com/logos-blockchain/logos-execution-zone.git?tag=v0.2.0-rc6#e37876a64028a335eb693198a1ed6a0e875ec5b4" +dependencies = [ + "anyhow", + "authenticated_transfer_core", + "base64", + "borsh", + "clock_core", + "hex", + "lee", + "lee_core", + "log", + "logos-blockchain-common-http-client", + "programs", + "serde", + "serde_with", + "sha2", + "system_accounts", + "thiserror 2.0.18", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "const-hex" version = "1.19.1" @@ -906,6 +1291,12 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" +[[package]] +name = "const-str" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f421161cb492475f1661ddc9815a745a1c894592070661180fdec3d4872e9c3" + [[package]] name = "const_format" version = "0.2.36" @@ -927,6 +1318,15 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "convert_case" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baaaa0ecca5b51987b9423ccdc971514dd8b0bb7b4060b983d3664dad3f1f89f" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "convert_case" version = "0.10.0" @@ -981,6 +1381,39 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d85363c37faeca707aef026efa9f3b34d077bce547e48f770770625c6013679e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" + [[package]] name = "crunchy" version = "0.2.4" @@ -993,7 +1426,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "generic-array", + "generic-array 0.14.9", "rand_core 0.6.4", "subtle", "zeroize", @@ -1005,7 +1438,8 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array", + "generic-array 0.14.9", + "rand_core 0.6.4", "typenum", ] @@ -1020,6 +1454,15 @@ dependencies = [ "rand_core 0.10.1", ] +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher 0.4.4", +] + [[package]] name = "ctutils" version = "0.4.2" @@ -1029,6 +1472,34 @@ dependencies = [ "cmov", ] +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "rustc_version 0.4.1", + "serde", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "darling" version = "0.20.11" @@ -1098,6 +1569,32 @@ dependencies = [ "syn 2.0.118", ] +[[package]] +name = "data-encoding" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8" + +[[package]] +name = "data-encoding-macro" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3259c913752a86488b501ed8680446a5ed2d5aeac6e596cb23ba3800768ea32c" +dependencies = [ + "data-encoding", + "data-encoding-macro-internal", +] + +[[package]] +name = "data-encoding-macro-internal" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccc2776f0c61eca1ca32528f85548abd1a4be8fb53d1b21c013e4f18da1e7090" +dependencies = [ + "data-encoding", + "syn 2.0.118", +] + [[package]] name = "der" version = "0.7.10" @@ -1119,6 +1616,20 @@ dependencies = [ "zeroize", ] +[[package]] +name = "der-parser" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom 7.1.3", + "num-bigint", + "num-traits", + "rusticata-macros", +] + [[package]] name = "deranged" version = "0.5.8" @@ -1185,7 +1696,7 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" dependencies = [ - "convert_case", + "convert_case 0.10.0", "proc-macro2", "quote", "rustc_version 0.4.1", @@ -1199,7 +1710,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "generic-array", + "generic-array 0.14.9", ] [[package]] @@ -1256,6 +1767,17 @@ dependencies = [ "syn 2.0.118", ] +[[package]] +name = "dlopen2" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b4f5f101177ff01b8ec4ecc81eead416a8aa42819a2869311b3420fa114ffa" +dependencies = [ + "libc", + "once_cell", + "winapi", +] + [[package]] name = "docker-generate" version = "0.1.3" @@ -1268,6 +1790,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" +[[package]] +name = "dtoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590" + [[package]] name = "duplicate" version = "2.0.1" @@ -1300,6 +1828,32 @@ dependencies = [ "spki 0.7.3", ] +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8 0.10.2", + "serde", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" +dependencies = [ + "curve25519-dalek", + "ed25519", + "rand_core 0.6.4", + "serde", + "sha2", + "subtle", + "zeroize", +] + [[package]] name = "educe" version = "0.6.0" @@ -1334,7 +1888,7 @@ dependencies = [ "crypto-bigint", "digest 0.10.7", "ff", - "generic-array", + "generic-array 0.14.9", "group", "pem-rfc7468", "pkcs8 0.10.2", @@ -1366,6 +1920,18 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "enum-as-inner" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "enum-ordinalize" version = "4.4.1" @@ -1402,6 +1968,27 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + [[package]] name = "eyre" version = "0.6.12" @@ -1440,6 +2027,26 @@ dependencies = [ "bytes", ] +[[package]] +name = "faucet_core" +version = "0.1.0" +source = "git+https://github.com/logos-blockchain/logos-execution-zone.git?tag=v0.2.0-rc6#e37876a64028a335eb693198a1ed6a0e875ec5b4" +dependencies = [ + "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.52.0", +] + [[package]] name = "ff" version = "0.13.1" @@ -1450,6 +2057,22 @@ dependencies = [ "subtle", ] +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "filetime" +version = "0.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759" +dependencies = [ + "cfg-if", + "libc", +] + [[package]] name = "find-msvc-tools" version = "0.1.9" @@ -1468,6 +2091,16 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + [[package]] name = "fnv" version = "1.0.7" @@ -1528,6 +2161,31 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" +[[package]] +name = "futures" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-bounded" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91f328e7fb845fc832912fb6a34f40cf6d1888c92f974d1893a54e97b5ff542e" +dependencies = [ + "futures-timer", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.32" @@ -1544,12 +2202,33 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" +[[package]] +name = "futures-executor" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + [[package]] name = "futures-io" version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" +[[package]] +name = "futures-lite" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" +dependencies = [ + "futures-core", + "pin-project-lite", +] + [[package]] name = "futures-macro" version = "0.3.32" @@ -1561,6 +2240,17 @@ dependencies = [ "syn 2.0.118", ] +[[package]] +name = "futures-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f2f12607f92c69b12ed746fabf9ca4f5c482cba46679c1a75b874ed7c26adb" +dependencies = [ + "futures-io", + "rustls", + "rustls-pki-types", +] + [[package]] name = "futures-sink" version = "0.3.32" @@ -1573,12 +2263,19 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" +[[package]] +name = "futures-timer" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af43fadb8a98512d547e37b4e92e0ced13e205c061b87b4623eff01d918d6968" + [[package]] name = "futures-util" version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ + "futures-channel", "futures-core", "futures-io", "futures-macro", @@ -1600,6 +2297,17 @@ dependencies = [ "zeroize", ] +[[package]] +name = "generic-array" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2e55f16dcf0e9c00efbe2e655ffe45fc98e7066b52bc92f8a79e64060a79351" +dependencies = [ + "rustversion", + "serde_core", + "typenum", +] + [[package]] name = "getrandom" version = "0.2.17" @@ -1639,6 +2347,16 @@ dependencies = [ "rand_core 0.10.1", ] +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + [[package]] name = "group" version = "0.13.0" @@ -1650,12 +2368,40 @@ dependencies = [ "subtle", ] +[[package]] +name = "h2" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cb093c84e8bd9b188d4c4a8cb6579fc016968d14c99882163cd3ff402a4f155" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.4.2", + "indexmap 2.14.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", +] + [[package]] name = "hashbrown" version = "0.15.5" @@ -1663,6 +2409,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", + "equivalent", "foldhash 0.1.5", ] @@ -1675,6 +2422,15 @@ dependencies = [ "foldhash 0.2.0", ] +[[package]] +name = "hashlink" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" +dependencies = [ + "hashbrown 0.14.5", +] + [[package]] name = "hashlink" version = "0.10.0" @@ -1690,6 +2446,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + [[package]] name = "hex" version = "0.4.3" @@ -1720,6 +2482,68 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" +[[package]] +name = "hex_fmt" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b07f60793ff0a4d9cef0f18e63b5357e06209987153a64648c972c1e5aff336f" + +[[package]] +name = "hickory-proto" +version = "0.25.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d00147af6310f4392a31680db52a3ed45a2e0f68eb18e8c3fe5537ecc96d9e2" +dependencies = [ + "async-recursion", + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna", + "ipnet", + "once_cell", + "rand 0.9.4", + "socket2 0.5.10", + "thiserror 2.0.18", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hickory-resolver" +version = "0.25.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5762f69ebdbd4ddb2e975cd24690bf21fe6b2604039189c26acddbc427f12887" +dependencies = [ + "cfg-if", + "futures-util", + "hickory-proto", + "ipconfig", + "moka", + "once_cell", + "parking_lot", + "rand 0.9.4", + "resolv-conf", + "smallvec", + "thiserror 2.0.18", + "tokio", + "tracing", +] + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + [[package]] name = "hmac" version = "0.12.1" @@ -1729,6 +2553,34 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "hmac-sha512" +version = "1.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "019ece39bbefc17f13f677a690328cb978dbf6790e141a3c24e66372cb38588b" + +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http" version = "1.4.2" @@ -1746,7 +2598,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http", + "http 1.4.2", ] [[package]] @@ -1757,7 +2609,7 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http", + "http 1.4.2", "http-body", "pin-project-lite", ] @@ -1768,6 +2620,18 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "humantime" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15cdd26707701c53297e2fa6afb323d55fbc1d0810c3aec078ae3ef0424c3c15" + [[package]] name = "hybrid-array" version = "0.4.13" @@ -1788,9 +2652,11 @@ dependencies = [ "bytes", "futures-channel", "futures-core", - "http", + "h2", + "http 1.4.2", "http-body", "httparse", + "httpdate", "itoa", "pin-project-lite", "smallvec", @@ -1804,7 +2670,7 @@ version = "0.27.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" dependencies = [ - "http", + "http 1.4.2", "hyper", "hyper-util", "rustls", @@ -1814,6 +2680,19 @@ dependencies = [ "webpki-roots", ] +[[package]] +name = "hyper-timeout" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" +dependencies = [ + "hyper", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", +] + [[package]] name = "hyper-util" version = "0.1.20" @@ -1824,14 +2703,14 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http", + "http 1.4.2", "http-body", "hyper", "ipnet", "libc", "percent-encoding", "pin-project-lite", - "socket2", + "socket2 0.6.4", "tokio", "tower-service", "tracing", @@ -1979,6 +2858,81 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "if-addrs" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0a05c691e1fae256cf7013d99dad472dc52d5543322761f83ec8d47eab40d2b" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "if-watch" +version = "3.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71c02a5161c313f0cbdbadc511611893584a10a7b6153cb554bdf83ddce99ec2" +dependencies = [ + "async-io", + "core-foundation", + "fnv", + "futures", + "if-addrs", + "ipnet", + "log", + "netlink-packet-core 0.8.1", + "netlink-packet-route 0.28.0", + "netlink-proto", + "netlink-sys", + "rtnetlink", + "system-configuration 0.7.0", + "tokio", + "windows", +] + +[[package]] +name = "igd-next" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76b0d7d4541def58a37bf8efc559683f21edce7c82f0d866c93ac21f7e098f93" +dependencies = [ + "async-trait", + "attohttpc 0.24.1", + "bytes", + "futures", + "http 1.4.2", + "http-body-util", + "hyper", + "hyper-util", + "log", + "rand 0.8.6", + "tokio", + "url", + "xmltree", +] + +[[package]] +name = "igd-next" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "516893339c97f6011282d5825ac94fc1c7aad5cad26bdc2d0cee068c0bf97f97" +dependencies = [ + "async-trait", + "attohttpc 0.30.1", + "bytes", + "futures", + "http 1.4.2", + "http-body-util", + "hyper", + "hyper-util", + "log", + "rand 0.9.4", + "tokio", + "url", + "xmltree", +] + [[package]] name = "impl-codec" version = "0.6.0" @@ -2034,6 +2988,15 @@ dependencies = [ "serde_core", ] +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array 0.14.9", +] + [[package]] name = "inout" version = "0.2.2" @@ -2052,6 +3015,7 @@ dependencies = [ "ata-methods", "ata_core", "clock_core", + "key_protocol", "lee", "lee_core", "stablecoin-methods", @@ -2062,6 +3026,19 @@ dependencies = [ "twap_oracle_core", ] +[[package]] +name = "ipconfig" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d40460c0ce33d6ce4b0630ad68ff63d6661961c48b6dba35e5a4d81cfb48222" +dependencies = [ + "socket2 0.6.4", + "widestring", + "windows-registry", + "windows-result", + "windows-sys 0.61.2", +] + [[package]] name = "ipnet" version = "2.12.0" @@ -2101,6 +3078,31 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" +[[package]] +name = "jf-crhf" +version = "0.2.0" +source = "git+https://github.com/EspressoSystems/jellyfish?tag=jf-crhf-v0.2.0#f1538793f7f0e391495cb17bbb0c8703ec5f689d" +dependencies = [ + "ark-serialize 0.5.0", + "ark-std 0.5.0", +] + +[[package]] +name = "jf-poseidon2" +version = "0.2.0" +source = "git+https://github.com/EspressoSystems/jellyfish.git?rev=8d80230358e900f8d63765a937f63f4978ca1daa#8d80230358e900f8d63765a937f63f4978ca1daa" +dependencies = [ + "ark-bn254", + "ark-ff 0.5.0", + "ark-std 0.5.0", + "displaydoc", + "hex", + "jf-crhf", + "lazy_static", + "spongefish", + "zeroize", +] + [[package]] name = "js-sys" version = "0.3.103" @@ -2166,6 +3168,28 @@ dependencies = [ "rand_core 0.10.1", ] +[[package]] +name = "key_protocol" +version = "0.1.0" +source = "git+https://github.com/logos-blockchain/logos-execution-zone.git?tag=v0.2.0-rc6#e37876a64028a335eb693198a1ed6a0e875ec5b4" +dependencies = [ + "aes-gcm", + "anyhow", + "bip39", + "common", + "hex", + "hmac-sha512", + "itertools 0.14.0", + "k256", + "lee", + "lee_core", + "ml-kem", + "rand 0.8.6", + "serde", + "sha2", + "thiserror 2.0.18", +] + [[package]] name = "konst" version = "0.2.20" @@ -2263,6 +3287,403 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" +[[package]] +name = "libp2p" +version = "0.55.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b72dc443ddd0254cb49a794ed6b6728400ee446a0f7ab4a07d0209ee98de20e9" +dependencies = [ + "bytes", + "either", + "futures", + "futures-timer", + "getrandom 0.2.17", + "libp2p-allow-block-list", + "libp2p-autonat", + "libp2p-connection-limits", + "libp2p-core", + "libp2p-dns", + "libp2p-gossipsub", + "libp2p-identify", + "libp2p-identity", + "libp2p-kad", + "libp2p-mdns", + "libp2p-metrics", + "libp2p-quic", + "libp2p-swarm", + "libp2p-tcp", + "libp2p-upnp", + "multiaddr", + "pin-project", + "rw-stream-sink", + "thiserror 2.0.18", +] + +[[package]] +name = "libp2p-allow-block-list" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38944b7cb981cc93f2f0fb411ff82d0e983bd226fbcc8d559639a3a73236568b" +dependencies = [ + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", +] + +[[package]] +name = "libp2p-autonat" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e297bfc6cabb70c6180707f8fa05661b77ecb9cb67e8e8e1c469301358fa21d0" +dependencies = [ + "async-trait", + "asynchronous-codec", + "either", + "futures", + "futures-bounded", + "futures-timer", + "libp2p-core", + "libp2p-identity", + "libp2p-request-response", + "libp2p-swarm", + "quick-protobuf", + "quick-protobuf-codec", + "rand 0.8.6", + "rand_core 0.6.4", + "thiserror 2.0.18", + "tracing", + "web-time", +] + +[[package]] +name = "libp2p-connection-limits" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efe9323175a17caa8a2ed4feaf8a548eeef5e0b72d03840a0eab4bcb0210ce1c" +dependencies = [ + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", +] + +[[package]] +name = "libp2p-core" +version = "0.43.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "249128cd37a2199aff30a7675dffa51caf073b51aa612d2f544b19932b9aebca" +dependencies = [ + "either", + "fnv", + "futures", + "futures-timer", + "libp2p-identity", + "multiaddr", + "multihash", + "multistream-select", + "parking_lot", + "pin-project", + "quick-protobuf", + "rand 0.8.6", + "rw-stream-sink", + "thiserror 2.0.18", + "tracing", + "unsigned-varint 0.8.0", + "web-time", +] + +[[package]] +name = "libp2p-dns" +version = "0.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b780a1150214155b0ed1cdf09fbd2e1b0442604f9146a431d1b21d23eef7bd7" +dependencies = [ + "async-trait", + "futures", + "hickory-resolver", + "libp2p-core", + "libp2p-identity", + "parking_lot", + "smallvec", + "tracing", +] + +[[package]] +name = "libp2p-gossipsub" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d558548fa3b5a8e9b66392f785921e363c57c05dcadfda4db0d41ae82d313e4a" +dependencies = [ + "async-channel", + "asynchronous-codec", + "base64", + "byteorder", + "bytes", + "either", + "fnv", + "futures", + "futures-timer", + "getrandom 0.2.17", + "hashlink 0.9.1", + "hex_fmt", + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "prometheus-client", + "quick-protobuf", + "quick-protobuf-codec", + "rand 0.8.6", + "regex", + "serde", + "sha2", + "tracing", + "web-time", +] + +[[package]] +name = "libp2p-identify" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8c06862544f02d05d62780ff590cc25a75f5c2b9df38ec7a370dcae8bb873cf" +dependencies = [ + "asynchronous-codec", + "either", + "futures", + "futures-bounded", + "futures-timer", + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "quick-protobuf", + "quick-protobuf-codec", + "smallvec", + "thiserror 2.0.18", + "tracing", +] + +[[package]] +name = "libp2p-identity" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9525f3831544f7ae497bde79adf114ef127b0fbbb97edbbf692a80408636421c" +dependencies = [ + "asn1_der", + "bs58", + "ed25519-dalek", + "hkdf", + "k256", + "multihash", + "prost 0.14.4", + "rand 0.8.6", + "serde", + "sha2", + "thiserror 2.0.18", + "tracing", + "zeroize", +] + +[[package]] +name = "libp2p-kad" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bab0466a27ebe955bcbc27328fae5429c5b48c915fd6174931414149802ec23" +dependencies = [ + "asynchronous-codec", + "bytes", + "either", + "fnv", + "futures", + "futures-bounded", + "futures-timer", + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "quick-protobuf", + "quick-protobuf-codec", + "rand 0.8.6", + "serde", + "sha2", + "smallvec", + "thiserror 2.0.18", + "tracing", + "uint 0.10.0", + "web-time", +] + +[[package]] +name = "libp2p-mdns" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d0ba095e1175d797540e16b62e7576846b883cb5046d4159086837b36846cc" +dependencies = [ + "futures", + "hickory-proto", + "if-watch", + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "rand 0.8.6", + "smallvec", + "socket2 0.5.10", + "tokio", + "tracing", +] + +[[package]] +name = "libp2p-metrics" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ce58c64292e87af624fcb86465e7dd8342e46a388d71e8fec0ab37ee789630a" +dependencies = [ + "futures", + "libp2p-core", + "libp2p-gossipsub", + "libp2p-identify", + "libp2p-identity", + "libp2p-kad", + "libp2p-swarm", + "pin-project", + "prometheus-client", + "web-time", +] + +[[package]] +name = "libp2p-quic" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41432a159b00424a0abaa2c80d786cddff81055ac24aa127e0cf375f7858d880" +dependencies = [ + "futures", + "futures-timer", + "if-watch", + "libp2p-core", + "libp2p-identity", + "libp2p-tls", + "quinn", + "rand 0.8.6", + "ring", + "rustls", + "socket2 0.5.10", + "thiserror 2.0.18", + "tokio", + "tracing", +] + +[[package]] +name = "libp2p-request-response" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "548fe44a80ff275d400f1b26b090d441d83ef73efabbeb6415f4ce37e5aed865" +dependencies = [ + "async-trait", + "futures", + "futures-bounded", + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "rand 0.8.6", + "smallvec", + "tracing", +] + +[[package]] +name = "libp2p-stream" +version = "0.3.0-alpha" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826716f1ee125895f1fb44911413cba023485b552ff96c7a2159bd037ac619bb" +dependencies = [ + "futures", + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "rand 0.8.6", + "tracing", +] + +[[package]] +name = "libp2p-swarm" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "803399b4b6f68adb85e63ab573ac568154b193e9a640f03e0f2890eabbcb37f8" +dependencies = [ + "either", + "fnv", + "futures", + "futures-timer", + "libp2p-core", + "libp2p-identity", + "libp2p-swarm-derive", + "lru", + "multistream-select", + "once_cell", + "rand 0.8.6", + "smallvec", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "libp2p-swarm-derive" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "206e0aa0ebe004d778d79fb0966aa0de996c19894e2c0605ba2f8524dd4443d8" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "libp2p-tcp" +version = "0.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65346fb4d36035b23fec4e7be4c320436ba53537ce9b6be1d1db1f70c905cad0" +dependencies = [ + "futures", + "futures-timer", + "if-watch", + "libc", + "libp2p-core", + "socket2 0.5.10", + "tokio", + "tracing", +] + +[[package]] +name = "libp2p-tls" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96ff65a82e35375cbc31ebb99cacbbf28cb6c4fefe26bf13756ddcf708d40080" +dependencies = [ + "futures", + "futures-rustls", + "libp2p-core", + "libp2p-identity", + "rcgen", + "ring", + "rustls", + "rustls-webpki", + "thiserror 2.0.18", + "x509-parser", + "yasna", +] + +[[package]] +name = "libp2p-upnp" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d457b9ecceb66e7199f049926fad447f1f17f040e8d29d690c086b4cab8ed14a" +dependencies = [ + "futures", + "futures-timer", + "igd-next 0.15.1", + "libp2p-core", + "libp2p-swarm", + "tokio", + "tracing", +] + [[package]] name = "libredox" version = "0.1.18" @@ -2272,6 +3693,18 @@ dependencies = [ "libc", ] +[[package]] +name = "light-poseidon" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47a1ccadd0bb5a32c196da536fd72c59183de24a055f6bf0513bf845fefab862" +dependencies = [ + "ark-bn254", + "ark-ff 0.5.0", + "num-bigint", + "thiserror 1.0.69", +] + [[package]] name = "linux-raw-sys" version = "0.12.1" @@ -2284,12 +3717,711 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + [[package]] name = "log" version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" +[[package]] +name = "logos-blockchain-blend-crypto" +version = "0.1.2" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160" +dependencies = [ + "blake2", + "logos-blockchain-groth16", + "logos-blockchain-poq", + "logos-blockchain-poseidon2", + "logos-blockchain-utils", + "rs-merkle-tree", + "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=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160" +dependencies = [ + "blake2", + "derivative", + "hex", + "itertools 0.14.0", + "logos-blockchain-blend-crypto", + "logos-blockchain-blend-proofs", + "logos-blockchain-core", + "logos-blockchain-cryptarchia-engine", + "logos-blockchain-groth16", + "logos-blockchain-key-management-system-keys", + "logos-blockchain-log-targets", + "logos-blockchain-utils", + "serde", + "serde_with", + "thiserror 2.0.18", + "tracing", + "zeroize", +] + +[[package]] +name = "logos-blockchain-blend-proofs" +version = "0.1.2" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160" +dependencies = [ + "ed25519-dalek", + "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", + "serde", + "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=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160" +dependencies = [ + "async-trait", + "derivative", + "logos-blockchain-core", + "overwatch", + "serde", + "tokio", + "tracing", +] + +[[package]] +name = "logos-blockchain-chain-service" +version = "0.1.2" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160" +dependencies = [ + "async-trait", + "bytes", + "derivative", + "futures", + "logos-blockchain-chain-broadcast-service", + "logos-blockchain-core", + "logos-blockchain-cryptarchia-engine", + "logos-blockchain-cryptarchia-sync", + "logos-blockchain-groth16", + "logos-blockchain-ledger", + "logos-blockchain-network-service", + "logos-blockchain-services-utils", + "logos-blockchain-storage-service", + "logos-blockchain-time-service", + "logos-blockchain-tracing", + "logos-blockchain-utils", + "overwatch", + "serde", + "serde_with", + "thiserror 2.0.18", + "time", + "tokio", + "tracing", + "tracing-futures", +] + +[[package]] +name = "logos-blockchain-circuits-build" +version = "0.5.3" +source = "git+https://github.com/logos-blockchain/logos-blockchain-circuits.git?tag=v0.5.3#127626881faa975aa8e9868422cf6bbb08fcb512" +dependencies = [ + "dirs", + "fd-lock", + "flate2", + "tar", + "ureq", +] + +[[package]] +name = "logos-blockchain-circuits-common" +version = "0.5.3" +source = "git+https://github.com/logos-blockchain/logos-blockchain-circuits.git?tag=v0.5.3#127626881faa975aa8e9868422cf6bbb08fcb512" +dependencies = [ + "logos-blockchain-circuits-types", +] + +[[package]] +name = "logos-blockchain-circuits-poc-sys" +version = "0.5.3" +source = "git+https://github.com/logos-blockchain/logos-blockchain-circuits.git?tag=v0.5.3#127626881faa975aa8e9868422cf6bbb08fcb512" +dependencies = [ + "logos-blockchain-circuits-build", + "logos-blockchain-circuits-common", + "logos-blockchain-circuits-types", +] + +[[package]] +name = "logos-blockchain-circuits-pol-sys" +version = "0.5.3" +source = "git+https://github.com/logos-blockchain/logos-blockchain-circuits.git?tag=v0.5.3#127626881faa975aa8e9868422cf6bbb08fcb512" +dependencies = [ + "logos-blockchain-circuits-build", + "logos-blockchain-circuits-common", + "logos-blockchain-circuits-types", +] + +[[package]] +name = "logos-blockchain-circuits-poq-sys" +version = "0.5.3" +source = "git+https://github.com/logos-blockchain/logos-blockchain-circuits.git?tag=v0.5.3#127626881faa975aa8e9868422cf6bbb08fcb512" +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=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160" +dependencies = [ + "rust-rapidsnark", +] + +[[package]] +name = "logos-blockchain-circuits-signature-sys" +version = "0.5.3" +source = "git+https://github.com/logos-blockchain/logos-blockchain-circuits.git?tag=v0.5.3#127626881faa975aa8e9868422cf6bbb08fcb512" +dependencies = [ + "logos-blockchain-circuits-build", + "logos-blockchain-circuits-common", + "logos-blockchain-circuits-types", +] + +[[package]] +name = "logos-blockchain-circuits-types" +version = "0.5.3" +source = "git+https://github.com/logos-blockchain/logos-blockchain-circuits.git?tag=v0.5.3#127626881faa975aa8e9868422cf6bbb08fcb512" +dependencies = [ + "bytes", + "libc", +] + +[[package]] +name = "logos-blockchain-common-http-client" +version = "0.1.2" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160" +dependencies = [ + "futures", + "hex", + "log", + "logos-blockchain-chain-broadcast-service", + "logos-blockchain-chain-service", + "logos-blockchain-core", + "logos-blockchain-groth16", + "logos-blockchain-http-api-common", + "logos-blockchain-key-management-system-keys", + "logos-blockchain-log-targets", + "reqwest", + "serde", + "serde_json", + "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=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160" +dependencies = [ + "ark-ff 0.5.0", + "bincode", + "blake2", + "bytes", + "const-hex", + "futures", + "hex", + "logos-blockchain-blend-proofs", + "logos-blockchain-cryptarchia-engine", + "logos-blockchain-groth16", + "logos-blockchain-key-management-system-keys", + "logos-blockchain-log-targets", + "logos-blockchain-mmr", + "logos-blockchain-poc", + "logos-blockchain-pol", + "logos-blockchain-poseidon2", + "logos-blockchain-utils", + "logos-blockchain-utxotree", + "multiaddr", + "nom 8.0.0", + "num-bigint", + "rpds", + "serde", + "strum", + "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=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160" +dependencies = [ + "logos-blockchain-pol", + "logos-blockchain-utils", + "serde", + "serde_with", + "thiserror 2.0.18", + "time", + "tokio", + "tracing", +] + +[[package]] +name = "logos-blockchain-cryptarchia-sync" +version = "0.1.2" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160" +dependencies = [ + "bytes", + "futures", + "libp2p", + "libp2p-stream", + "logos-blockchain-core", + "logos-blockchain-cryptarchia-engine", + "rand 0.8.6", + "serde", + "serde_with", + "thiserror 2.0.18", + "tokio", + "tracing", +] + +[[package]] +name = "logos-blockchain-groth16" +version = "0.1.2" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160" +dependencies = [ + "ark-bn254", + "ark-ec", + "ark-ff 0.5.0", + "ark-groth16", + "ark-serialize 0.5.0", + "generic-array 1.4.3", + "hex", + "num-bigint", + "serde", + "serde_json", + "thiserror 2.0.18", +] + +[[package]] +name = "logos-blockchain-http-api-common" +version = "0.1.2" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160" +dependencies = [ + "axum", + "logos-blockchain-core", + "logos-blockchain-key-management-system-keys", + "logos-blockchain-log-targets", + "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=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160" +dependencies = [ + "async-trait", + "bytes", + "ed25519-dalek", + "generic-array 1.4.3", + "hex", + "logos-blockchain-groth16", + "logos-blockchain-key-management-system-macros", + "logos-blockchain-log-targets", + "logos-blockchain-poseidon2", + "logos-blockchain-utils", + "logos-blockchain-zksign", + "num-bigint", + "rand_core 0.6.4", + "serde", + "subtle", + "thiserror 2.0.18", + "tokio", + "tracing", + "x25519-dalek", + "zeroize", +] + +[[package]] +name = "logos-blockchain-key-management-system-macros" +version = "0.1.2" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "logos-blockchain-ledger" +version = "0.1.2" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160" +dependencies = [ + "derivative", + "logos-blockchain-blend-crypto", + "logos-blockchain-blend-message", + "logos-blockchain-blend-proofs", + "logos-blockchain-core", + "logos-blockchain-cryptarchia-engine", + "logos-blockchain-groth16", + "logos-blockchain-key-management-system-keys", + "logos-blockchain-mmr", + "logos-blockchain-pol", + "logos-blockchain-utils", + "logos-blockchain-utxotree", + "num-bigint", + "rand 0.8.6", + "rpds", + "serde", + "serde_arrays", + "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=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160" +dependencies = [ + "async-trait", + "backon", + "blake2", + "either", + "futures", + "hex", + "igd-next 0.16.2", + "libp2p", + "logos-blockchain-cryptarchia-sync", + "logos-blockchain-log-targets", + "logos-blockchain-utils", + "multiaddr", + "natpmp", + "netdev", + "num_enum", + "rand 0.8.6", + "serde", + "serde_with", + "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=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160" +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=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "logos-blockchain-mmr" +version = "0.1.2" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160" +dependencies = [ + "ark-ff 0.5.0", + "logos-blockchain-groth16", + "logos-blockchain-poseidon2", + "rpds", + "serde", + "thiserror 2.0.18", +] + +[[package]] +name = "logos-blockchain-network-service" +version = "0.1.2" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160" +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", + "rand_chacha 0.3.1", + "serde", + "tokio", + "tokio-stream", + "tracing", +] + +[[package]] +name = "logos-blockchain-poc" +version = "0.1.2" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160" +dependencies = [ + "logos-blockchain-circuits-poc-sys", + "logos-blockchain-circuits-prover", + "logos-blockchain-circuits-types", + "logos-blockchain-groth16", + "logos-blockchain-log-targets", + "logos-blockchain-proofs-error", + "num-bigint", + "serde", + "serde_json", + "tracing", +] + +[[package]] +name = "logos-blockchain-pol" +version = "0.1.2" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160" +dependencies = [ + "astro-float", + "logos-blockchain-circuits-pol-sys", + "logos-blockchain-circuits-prover", + "logos-blockchain-circuits-types", + "logos-blockchain-groth16", + "logos-blockchain-log-targets", + "logos-blockchain-proofs-error", + "logos-blockchain-utils", + "num-bigint", + "num-traits", + "serde", + "serde_json", + "tracing", +] + +[[package]] +name = "logos-blockchain-poq" +version = "0.1.2" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160" +dependencies = [ + "logos-blockchain-circuits-poq-sys", + "logos-blockchain-circuits-prover", + "logos-blockchain-circuits-types", + "logos-blockchain-groth16", + "logos-blockchain-log-targets", + "logos-blockchain-pol", + "logos-blockchain-proofs-error", + "num-bigint", + "serde", + "serde_json", + "thiserror 2.0.18", + "tracing", +] + +[[package]] +name = "logos-blockchain-poseidon2" +version = "0.1.2" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160" +dependencies = [ + "ark-bn254", + "ark-ff 0.5.0", + "jf-poseidon2", + "num-bigint", +] + +[[package]] +name = "logos-blockchain-proofs-error" +version = "0.1.2" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160" +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=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160" +dependencies = [ + "async-trait", + "futures", + "log", + "logos-blockchain-log-targets", + "overwatch", + "serde", + "serde_json", + "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=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160" +dependencies = [ + "async-trait", + "bytes", + "futures", + "logos-blockchain-core", + "logos-blockchain-cryptarchia-engine", + "logos-blockchain-log-targets", + "logos-blockchain-tracing", + "overwatch", + "serde", + "thiserror 2.0.18", + "tokio", + "tracing", +] + +[[package]] +name = "logos-blockchain-time-service" +version = "0.1.2" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160" +dependencies = [ + "async-trait", + "futures", + "log", + "logos-blockchain-cryptarchia-engine", + "logos-blockchain-log-targets", + "logos-blockchain-tracing", + "logos-blockchain-utils", + "overwatch", + "serde", + "serde_with", + "sntpc", + "thiserror 2.0.18", + "time", + "tokio", + "tokio-stream", + "tracing", +] + +[[package]] +name = "logos-blockchain-tracing" +version = "0.1.2" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160" +dependencies = [ + "flate2", + "logos-blockchain-log-targets", + "opentelemetry", + "opentelemetry-appender-tracing", + "opentelemetry-http", + "opentelemetry-otlp", + "opentelemetry-semantic-conventions", + "opentelemetry_sdk", + "rand 0.8.6", + "serde", + "tokio", + "tonic", + "tracing", + "tracing-appender", + "tracing-gelf", + "tracing-loki", + "tracing-opentelemetry", + "tracing-subscriber 0.3.23", + "url", +] + +[[package]] +name = "logos-blockchain-utils" +version = "0.1.2" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160" +dependencies = [ + "async-trait", + "blake2", + "cipher 0.4.4", + "const-hex", + "humantime", + "logos-blockchain-log-targets", + "overwatch", + "rand 0.8.6", + "serde", + "serde_ignored", + "serde_with", + "serde_yaml", + "thiserror 2.0.18", + "time", + "tracing", +] + +[[package]] +name = "logos-blockchain-utxotree" +version = "0.1.2" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160" +dependencies = [ + "ark-ff 0.5.0", + "logos-blockchain-groth16", + "logos-blockchain-poseidon2", + "num-bigint", + "rpds", + "serde", + "thiserror 2.0.18", +] + +[[package]] +name = "logos-blockchain-zksign" +version = "0.1.2" +source = "git+https://github.com/logos-blockchain/logos-blockchain.git?rev=d8711bbc3d43d3ef9755ef9b73af32fd0f703160#d8711bbc3d43d3ef9755ef9b73af32fd0f703160" +dependencies = [ + "logos-blockchain-circuits-prover", + "logos-blockchain-circuits-signature-sys", + "logos-blockchain-circuits-types", + "logos-blockchain-groth16", + "logos-blockchain-log-targets", + "logos-blockchain-poseidon2", + "logos-blockchain-proofs-error", + "num-bigint", + "serde", + "serde_json", + "thiserror 2.0.18", + "tracing", +] + +[[package]] +name = "loki-api" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdc38a304f59a03e6efa3876766a48c70a766a93f88341c3fff4212834b8e327" +dependencies = [ + "prost 0.13.5", + "prost-types", +] + +[[package]] +name = "lru" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +dependencies = [ + "hashbrown 0.15.5", +] + [[package]] name = "lru-slab" version = "0.1.2" @@ -2305,6 +4437,38 @@ dependencies = [ "libc", ] +[[package]] +name = "match-lookup" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "757aee279b8bdbb9f9e676796fd459e4207a1f986e87886700abf589f5abf771" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + [[package]] name = "maybe-async" version = "0.2.11" @@ -2349,6 +4513,28 @@ dependencies = [ "paste", ] +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + [[package]] name = "mio" version = "1.2.1" @@ -2371,7 +4557,7 @@ dependencies = [ "module-lattice", "pkcs8 0.11.0", "rand_core 0.10.1", - "sha3", + "sha3 0.11.0", ] [[package]] @@ -2385,12 +4571,239 @@ dependencies = [ "num-traits", ] +[[package]] +name = "moka" +version = "0.12.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957228ad12042ee839f93c8f257b62b4c0ab5eaae1d4fa60de53b27c9d7c5046" +dependencies = [ + "crossbeam-channel", + "crossbeam-epoch", + "crossbeam-utils", + "equivalent", + "parking_lot", + "portable-atomic", + "smallvec", + "tagptr", + "uuid", +] + +[[package]] +name = "multiaddr" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe6351f60b488e04c1d21bc69e56b89cb3f5e8f5d22557d6e8031bdfd79b6961" +dependencies = [ + "arrayref", + "byteorder", + "data-encoding", + "libp2p-identity", + "multibase", + "multihash", + "percent-encoding", + "serde", + "static_assertions", + "unsigned-varint 0.8.0", + "url", +] + +[[package]] +name = "multibase" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e0e4a371cbf1dfd666b658ba137763edb23c45beb43cfe369b5593cd6b437b6" +dependencies = [ + "base-x", + "base256emoji", + "base45", + "data-encoding", + "data-encoding-macro", +] + +[[package]] +name = "multihash" +version = "0.19.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "577c63b00ad74d57e8c9aa870b5fccebf2fd64a308a5aee9f1bb88e4aea19447" +dependencies = [ + "serde", + "unsigned-varint 0.8.0", +] + +[[package]] +name = "multistream-select" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea0df8e5eec2298a62b326ee4f0d7fe1a6b90a09dfcf9df37b38f947a8c42f19" +dependencies = [ + "bytes", + "futures", + "log", + "pin-project", + "smallvec", + "unsigned-varint 0.7.2", +] + +[[package]] +name = "natpmp" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77366fa8ce34e2e1322dd97da65f11a62f451bd3daae8be6993c00800f61dd07" +dependencies = [ + "async-trait", + "cc", + "netdev", + "tokio", +] + +[[package]] +name = "netdev" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f901362e84cd407be6f8cd9d3a46bccf09136b095792785401ea7d283c79b91d" +dependencies = [ + "dlopen2", + "ipnet", + "libc", + "netlink-packet-core 0.7.0", + "netlink-packet-route 0.17.1", + "netlink-sys", + "once_cell", + "system-configuration 0.6.1", + "windows-sys 0.52.0", +] + +[[package]] +name = "netlink-packet-core" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72724faf704479d67b388da142b186f916188505e7e0b26719019c525882eda4" +dependencies = [ + "anyhow", + "byteorder", + "netlink-packet-utils", +] + +[[package]] +name = "netlink-packet-core" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3463cbb78394cb0141e2c926b93fc2197e473394b761986eca3b9da2c63ae0f4" +dependencies = [ + "paste", +] + +[[package]] +name = "netlink-packet-route" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053998cea5a306971f88580d0829e90f270f940befd7cf928da179d4187a5a66" +dependencies = [ + "anyhow", + "bitflags 1.3.2", + "byteorder", + "libc", + "netlink-packet-core 0.7.0", + "netlink-packet-utils", +] + +[[package]] +name = "netlink-packet-route" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ce3636fa715e988114552619582b530481fd5ef176a1e5c1bf024077c2c9445" +dependencies = [ + "bitflags 2.13.0", + "libc", + "log", + "netlink-packet-core 0.8.1", +] + +[[package]] +name = "netlink-packet-utils" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ede8a08c71ad5a95cdd0e4e52facd37190977039a4704eb82a283f713747d34" +dependencies = [ + "anyhow", + "byteorder", + "paste", + "thiserror 1.0.69", +] + +[[package]] +name = "netlink-proto" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b65d130ee111430e47eed7896ea43ca693c387f097dd97376bffafbf25812128" +dependencies = [ + "bytes", + "futures", + "log", + "netlink-packet-core 0.8.1", + "netlink-sys", + "thiserror 2.0.18", +] + +[[package]] +name = "netlink-sys" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd6c30ed10fa69cc491d491b85cc971f6bdeb8e7367b7cde2ee6cc878d583fae" +dependencies = [ + "bytes", + "futures-util", + "libc", + "log", + "tokio", +] + +[[package]] +name = "nix" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" +dependencies = [ + "bitflags 2.13.0", + "cfg-if", + "cfg_aliases", + "libc", +] + [[package]] name = "no_std_strings" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5b0c77c1b780822bc749a33e39aeb2c07584ab93332303babeabb645298a76e" +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nom" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" +dependencies = [ + "memchr", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "num-bigint" version = "0.4.6" @@ -2483,18 +4896,152 @@ dependencies = [ "malloc_buf", ] +[[package]] +name = "oid-registry" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" +dependencies = [ + "asn1-rs", +] + [[package]] name = "once_cell" version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "opentelemetry" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b84bcd6ae87133e903af7ef497404dda70c60d0ea14895fc8a5e6722754fc2a0" +dependencies = [ + "futures-core", + "futures-sink", + "js-sys", + "pin-project-lite", + "thiserror 2.0.18", +] + +[[package]] +name = "opentelemetry-appender-tracing" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef6a1ac5ca3accf562b8c306fa8483c85f4390f768185ab775f242f7fe8fdcc2" +dependencies = [ + "opentelemetry", + "tracing", + "tracing-core", + "tracing-subscriber 0.3.23", +] + +[[package]] +name = "opentelemetry-http" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a6d09a73194e6b66df7c8f1b680f156d916a1a942abf2de06823dd02b7855d" +dependencies = [ + "async-trait", + "bytes", + "http 1.4.2", + "opentelemetry", + "reqwest", +] + +[[package]] +name = "opentelemetry-otlp" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f69cd6acbb9af919df949cd1ec9e5e7fdc2ef15d234b6b795aaa525cc02f71f" +dependencies = [ + "http 1.4.2", + "opentelemetry", + "opentelemetry-http", + "opentelemetry-proto", + "opentelemetry_sdk", + "prost 0.14.4", + "reqwest", + "thiserror 2.0.18", + "tokio", + "tonic", +] + +[[package]] +name = "opentelemetry-proto" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7175df06de5eaee9909d4805a3d07e28bb752c34cab57fa9cff549da596b30f" +dependencies = [ + "opentelemetry", + "opentelemetry_sdk", + "prost 0.14.4", + "tonic", + "tonic-prost", +] + +[[package]] +name = "opentelemetry-semantic-conventions" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e62e29dfe041afb8ed2a6c9737ab57db4907285d999ef8ad3a59092a36bdc846" + +[[package]] +name = "opentelemetry_sdk" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ae4f5991976fd48df6d843de219ca6d31b01daaab2dad5af2badeded372bd" +dependencies = [ + "futures-channel", + "futures-executor", + "futures-util", + "opentelemetry", + "percent-encoding", + "rand 0.9.4", + "thiserror 2.0.18", + "tokio", + "tokio-stream", +] + [[package]] name = "option-ext" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "overwatch" +version = "0.1.0" +source = "git+https://github.com/logos-co/Overwatch?rev=448c192#448c192895b8311c742b1726a1bb12ee314ad95c" +dependencies = [ + "async-trait", + "futures", + "overwatch-derive", + "thiserror 2.0.18", + "tokio", + "tokio-stream", + "tokio-util", + "tracing", +] + +[[package]] +name = "overwatch-derive" +version = "0.1.0" +source = "git+https://github.com/logos-co/Overwatch?rev=448c192#448c192895b8311c742b1726a1bb12ee314ad95c" +dependencies = [ + "convert_case 0.8.0", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "parity-scale-codec" version = "3.7.5" @@ -2523,12 +5070,51 @@ dependencies = [ "syn 2.0.118", ] +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + [[package]] name = "paste" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pem" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" +dependencies = [ + "base64", + "serde_core", +] + [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -2554,6 +5140,26 @@ dependencies = [ "ucd-trie", ] +[[package]] +name = "pin-project" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "pin-project-lite" version = "0.2.17" @@ -2591,6 +5197,38 @@ dependencies = [ "spki 0.8.0", ] +[[package]] +name = "polling" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi", + "pin-project-lite", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + [[package]] name = "postcard" version = "1.1.3" @@ -2635,7 +5273,7 @@ checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" dependencies = [ "fixed-hash", "impl-codec", - "uint", + "uint 0.9.5", ] [[package]] @@ -2647,6 +5285,52 @@ dependencies = [ "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]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "proc-macro2" version = "1.0.106" @@ -2668,6 +5352,38 @@ dependencies = [ "version_check", ] +[[package]] +name = "programs" +version = "0.1.0" +source = "git+https://github.com/logos-blockchain/logos-execution-zone.git?tag=v0.2.0-rc6#e37876a64028a335eb693198a1ed6a0e875ec5b4" +dependencies = [ + "build_utils", + "lee", +] + +[[package]] +name = "prometheus-client" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "504ee9ff529add891127c4827eb481bd69dc0ebc72e9a682e187db4caa60c3ca" +dependencies = [ + "dtoa", + "itoa", + "parking_lot", + "prometheus-client-derive-encode", +] + +[[package]] +name = "prometheus-client-derive-encode" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "proptest" version = "1.11.0" @@ -2694,7 +5410,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" dependencies = [ "bytes", - "prost-derive", + "prost-derive 0.13.5", +] + +[[package]] +name = "prost" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528ac67416ff8646872a3c02cad9cc4ee5dc9f9540c9b10771855c95cb2e5ae1" +dependencies = [ + "bytes", + "prost-derive 0.14.4", ] [[package]] @@ -2710,12 +5436,56 @@ dependencies = [ "syn 2.0.118", ] +[[package]] +name = "prost-derive" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b570b25f7617e43d59005d0990ccb79e950a423952cea19671b7a876da390adf" +dependencies = [ + "anyhow", + "itertools 0.14.0", + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "prost-types" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" +dependencies = [ + "prost 0.13.5", +] + [[package]] name = "quick-error" version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +[[package]] +name = "quick-protobuf" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d6da84cc204722a989e01ba2f6e1e276e190f22263d0cb6ce8526fcdb0d2e1f" +dependencies = [ + "byteorder", +] + +[[package]] +name = "quick-protobuf-codec" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15a0580ab32b169745d7a39db2ba969226ca16738931be152a3209b409de2474" +dependencies = [ + "asynchronous-codec", + "bytes", + "quick-protobuf", + "thiserror 1.0.69", + "unsigned-varint 0.8.0", +] + [[package]] name = "quinn" version = "0.11.11" @@ -2724,12 +5494,13 @@ checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8" dependencies = [ "bytes", "cfg_aliases", + "futures-io", "pin-project-lite", "quinn-proto", "quinn-udp", "rustc-hash", "rustls", - "socket2", + "socket2 0.6.4", "thiserror 2.0.18", "tokio", "tracing", @@ -2766,7 +5537,7 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2", + "socket2 0.6.4", "tracing", "windows-sys 0.60.2", ] @@ -2881,6 +5652,28 @@ dependencies = [ "rustversion", ] +[[package]] +name = "rcgen" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75e669e5202259b5314d1ea5397316ad400819437857b90861765f24c4cf80a2" +dependencies = [ + "pem", + "ring", + "rustls-pki-types", + "time", + "yasna", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.13.0", +] + [[package]] name = "redox_users" version = "0.5.2" @@ -2952,7 +5745,8 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "http", + "h2", + "http 1.4.2", "http-body", "http-body-util", "hyper", @@ -2983,6 +5777,12 @@ dependencies = [ "webpki-roots", ] +[[package]] +name = "resolv-conf" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e061d1b48cb8d38042de4ae0a7a6401009d6143dc80d2e2d6f31f0bdd6470c7" + [[package]] name = "rfc6979" version = "0.4.0" @@ -3193,7 +5993,7 @@ dependencies = [ "derive_more", "hex", "lazy-regex", - "prost", + "prost 0.13.5", "risc0-binfmt", "risc0-build", "risc0-circuit-keccak", @@ -3240,6 +6040,17 @@ dependencies = [ "rustc-hex", ] +[[package]] +name = "rpds" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e025feb26210bc196b908e72deb063b1b4000754304341cbc168a1e72c857ebc" +dependencies = [ + "archery", + "serde", + "smallvec", +] + [[package]] name = "rrs-lib" version = "0.1.0" @@ -3250,6 +6061,25 @@ dependencies = [ "paste", ] +[[package]] +name = "rs-merkle-tree" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7a3ef170810c387d31b64c0b59734abb0839dac2a8d137909e271bfdec9b1e0" +dependencies = [ + "ark-bn254", + "ark-ff 0.5.0", + "byteorder", + "futures", + "light-poseidon", + "quote", + "rand 0.9.4", + "syn 1.0.109", + "thiserror 2.0.18", + "tiny-keccak", + "tokio", +] + [[package]] name = "rsa" version = "0.9.10" @@ -3270,6 +6100,24 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rtnetlink" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b960d5d873a75b5be9761b1e73b146f52dddcd27bac75263f40fba686d4d7b5" +dependencies = [ + "futures-channel", + "futures-util", + "log", + "netlink-packet-core 0.8.1", + "netlink-packet-route 0.28.0", + "netlink-proto", + "netlink-sys", + "nix", + "thiserror 1.0.69", + "tokio", +] + [[package]] name = "ruint" version = "1.17.0" @@ -3305,6 +6153,18 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" +[[package]] +name = "rust-rapidsnark" +version = "0.1.3" +source = "git+https://github.com/logos-blockchain/logos-blockchain-rust-rapidsnark.git?rev=e91187f8ccb5bbfc7bb00dac88169112428da78f#e91187f8ccb5bbfc7bb00dac88169112428da78f" +dependencies = [ + "anyhow", + "cc", + "chkstk_stub", + "num-bigint", + "num-traits", +] + [[package]] name = "rustc-hash" version = "2.1.2" @@ -3335,6 +6195,15 @@ dependencies = [ "semver 1.0.28", ] +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom 7.1.3", +] + [[package]] name = "rustix" version = "1.1.4" @@ -3354,6 +6223,7 @@ version = "0.23.41" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b92b125634d9b795e7beca796cc790df15a7fb38323bf3196fda83292d06b1f" dependencies = [ + "log", "once_cell", "ring", "rustls-pki-types", @@ -3401,6 +6271,17 @@ dependencies = [ "wait-timeout", ] +[[package]] +name = "rw-stream-sink" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8c9026ff5d2f23da5e45bbc283f156383001bfb09c4e44256d02c1a685fe9a1" +dependencies = [ + "futures", + "pin-project", + "static_assertions", +] + [[package]] name = "ryu" version = "1.0.23" @@ -3450,6 +6331,12 @@ dependencies = [ "serde_json", ] +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "sec1" version = "0.7.3" @@ -3458,7 +6345,7 @@ checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", "der 0.7.10", - "generic-array", + "generic-array 0.14.9", "pkcs8 0.10.2", "serdect", "subtle", @@ -3523,6 +6410,15 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde_arrays" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94a16b99c5ea4fe3daccd14853ad260ec00ea043b2708d1fd1da3106dcd8d9df" +dependencies = [ + "serde", +] + [[package]] name = "serde_core" version = "1.0.228" @@ -3543,6 +6439,16 @@ dependencies = [ "syn 2.0.118", ] +[[package]] +name = "serde_ignored" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115dffd5f3853e06e746965a20dcbae6ee747ae30b543d91b0e089668bb07798" +dependencies = [ + "serde", + "serde_core", +] + [[package]] name = "serde_json" version = "1.0.150" @@ -3557,6 +6463,17 @@ dependencies = [ "zmij", ] +[[package]] +name = "serde_path_to_error" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" +dependencies = [ + "itoa", + "serde", + "serde_core", +] + [[package]] name = "serde_spanned" version = "0.6.9" @@ -3610,6 +6527,19 @@ dependencies = [ "syn 2.0.118", ] +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap 2.14.0", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "serdect" version = "0.2.0" @@ -3631,6 +6561,16 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "sha3" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77fd7028345d415a4034cf8777cd4f8ab1851274233b45f84e3d955502d93874" +dependencies = [ + "digest 0.10.7", + "keccak 0.1.6", +] + [[package]] name = "sha3" version = "0.11.0" @@ -3651,12 +6591,31 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + [[package]] name = "signature" version = "2.2.0" @@ -3667,6 +6626,12 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "simd-adler32" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + [[package]] name = "slab" version = "0.4.12" @@ -3679,6 +6644,32 @@ version = "1.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" +[[package]] +name = "snap" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" + +[[package]] +name = "sntpc" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78f778a0f82b3cf5d75f858eceee38e84d5292f1d03415e88cc4ec45ca6ba8a2" +dependencies = [ + "cfg-if", + "tokio", +] + +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "socket2" version = "0.6.4" @@ -3745,6 +6736,24 @@ dependencies = [ "der 0.8.0", ] +[[package]] +name = "spongefish" +version = "0.2.0" +source = "git+https://github.com/arkworks-rs/spongefish.git?rev=3ded547f7f56d7f8a1fc4c9a5c0ce965310bba5f#3ded547f7f56d7f8a1fc4c9a5c0ce965310bba5f" +dependencies = [ + "ark-ec", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "digest 0.10.7", + "hex", + "keccak 0.1.6", + "rand 0.8.6", + "sha3 0.10.9", + "thiserror 2.0.18", + "zerocopy", + "zeroize", +] + [[package]] name = "stability" version = "0.2.1" @@ -3832,6 +6841,12 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +[[package]] +name = "symlink" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7973cce6668464ea31f176d85b13c7ab3bba2cb3b77a2ed26abd7801688010a" + [[package]] name = "syn" version = "1.0.109" @@ -3874,12 +6889,73 @@ dependencies = [ "syn 2.0.118", ] +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags 2.13.0", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" +dependencies = [ + "bitflags 2.13.0", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "system_accounts" +version = "0.1.0" +source = "git+https://github.com/logos-blockchain/logos-execution-zone.git?tag=v0.2.0-rc6#e37876a64028a335eb693198a1ed6a0e875ec5b4" +dependencies = [ + "bridge_core", + "clock_core", + "faucet_core", + "lee_core", + "programs", +] + +[[package]] +name = "tagptr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" + [[package]] name = "tap" 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 = "tempfile" version = "3.27.0" @@ -3933,6 +7009,15 @@ dependencies = [ "syn 2.0.118", ] +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + [[package]] name = "time" version = "0.3.53" @@ -3963,6 +7048,15 @@ dependencies = [ "time-core", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinystr" version = "0.8.3" @@ -4024,11 +7118,25 @@ dependencies = [ "bytes", "libc", "mio", + "parking_lot", "pin-project-lite", - "socket2", + "signal-hook-registry", + "socket2 0.6.4", + "tokio-macros", "windows-sys 0.61.2", ] +[[package]] +name = "tokio-macros" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "tokio-rustls" version = "0.26.4" @@ -4039,6 +7147,18 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-stream" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", + "tokio-util", +] + [[package]] name = "tokio-util" version = "0.7.18" @@ -4123,6 +7243,43 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" +[[package]] +name = "tonic" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac2a5518c70fa84342385732db33fb3f44bc4cc748936eb5833d2df34d6445ef" +dependencies = [ + "async-trait", + "base64", + "bytes", + "http 1.4.2", + "http-body", + "http-body-util", + "hyper", + "hyper-timeout", + "hyper-util", + "percent-encoding", + "pin-project", + "sync_wrapper", + "tokio", + "tokio-stream", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tonic-prost" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50849f68853be452acf590cde0b146665b8d507b3b8af17261df47e02c209ea0" +dependencies = [ + "bytes", + "prost 0.14.4", + "tonic", +] + [[package]] name = "tower" version = "0.5.3" @@ -4131,11 +7288,15 @@ checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", + "indexmap 2.14.0", "pin-project-lite", + "slab", "sync_wrapper", "tokio", + "tokio-util", "tower-layer", "tower-service", + "tracing", ] [[package]] @@ -4147,7 +7308,7 @@ dependencies = [ "bitflags 2.13.0", "bytes", "futures-util", - "http", + "http 1.4.2", "http-body", "pin-project-lite", "tower", @@ -4180,6 +7341,19 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-appender" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "050686193eb999b4bb3bc2acfa891a13da00f79734704c4b8b4ef1a10b368a3c" +dependencies = [ + "crossbeam-channel", + "symlink", + "thiserror 2.0.18", + "time", + "tracing-subscriber 0.3.23", +] + [[package]] name = "tracing-attributes" version = "0.1.31" @@ -4201,6 +7375,91 @@ dependencies = [ "valuable", ] +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + +[[package]] +name = "tracing-gelf" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c0170f1bf67b749d4377c2da1d99d6e722600051ee53870cfb6f618611e29e" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "hostname", + "serde_json", + "thiserror 1.0.69", + "tokio", + "tokio-util", + "tracing-core", + "tracing-futures", + "tracing-subscriber 0.3.23", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-loki" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d1ad78bf74c1790b0825ddc35ad1bb9498736c51c8437796b81cadf4916cd8" +dependencies = [ + "loki-api", + "reqwest", + "serde", + "serde_json", + "snap", + "tokio", + "tracing", + "tracing-core", + "tracing-log", + "tracing-serde", + "tracing-subscriber 0.3.23", + "url", +] + +[[package]] +name = "tracing-opentelemetry" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ac28f2d093c6c477eaa76b23525478f38de514fa9aeb1285738d4b97a9552fc" +dependencies = [ + "js-sys", + "opentelemetry", + "smallvec", + "tracing", + "tracing-core", + "tracing-subscriber 0.3.23", + "web-time", +] + +[[package]] +name = "tracing-serde" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" +dependencies = [ + "serde", + "tracing-core", +] + [[package]] name = "tracing-subscriber" version = "0.2.25" @@ -4210,6 +7469,30 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-subscriber" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "triomphe" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b40688ea6389c8171614b25491f71d4a27946e0c7ce2da1c6de27e25abf1a0ae" + [[package]] name = "try-lock" version = "0.2.5" @@ -4272,6 +7555,18 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "uint" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "909988d098b2f738727b161a106cfc7cab00c539c2687a8836f8e565976fb53e" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + [[package]] name = "unarray" version = "0.1.4" @@ -4284,6 +7579,15 @@ version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "unicode-normalization" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +dependencies = [ + "tinyvec", +] + [[package]] name = "unicode-segmentation" version = "1.13.3" @@ -4307,12 +7611,69 @@ dependencies = [ "thiserror 2.0.18", ] +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common 0.1.6", + "subtle", +] + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "unsigned-varint" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6889a77d49f1f013504cec6bf97a2c730394adedaeb1deb5ea08949a50541105" + +[[package]] +name = "unsigned-varint" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb066959b24b5196ae73cb057f45598450d2c5f71460e98c49b738086eff9c06" + [[package]] name = "untrusted" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "ureq" +version = "3.3.0" +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]] +name = "ureq-proto" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e994ba84b0bd1b1b0cf92878b7ef898a5c1760108fe7b6010327e274917a808c" +dependencies = [ + "base64", + "http 1.4.2", + "httparse", + "log", +] + [[package]] name = "url" version = "2.5.8" @@ -4323,14 +7684,86 @@ dependencies = [ "idna", "percent-encoding", "serde", + "serde_derive", ] +[[package]] +name = "utf8-zero" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8c0a043c9540bae7c578c88f91dda8bd82e59ae27c21baca69c8b191aaf5a6e" + [[package]] name = "utf8_iter" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "utoipa" +version = "4.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +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.118", +] + +[[package]] +name = "uuid" +version = "1.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf80a72845275afea99e7f2b434723d3bc7e38470fcd1c7ed39a599c73319a53" +dependencies = [ + "getrandom 0.4.3", + "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.118", +] + [[package]] name = "valuable" version = "0.1.1" @@ -4473,6 +7906,55 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "widestring" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" +dependencies = [ + "windows-collections", + "windows-core", + "windows-future", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" +dependencies = [ + "windows-core", +] + [[package]] name = "windows-core" version = "0.62.2" @@ -4486,6 +7968,17 @@ dependencies = [ "windows-strings", ] +[[package]] +name = "windows-future" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" +dependencies = [ + "windows-core", + "windows-link", + "windows-threading", +] + [[package]] name = "windows-implement" version = "0.60.2" @@ -4514,6 +8007,27 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-numerics" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" +dependencies = [ + "windows-core", + "windows-link", +] + +[[package]] +name = "windows-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" +dependencies = [ + "windows-link", + "windows-result", + "windows-strings", +] + [[package]] name = "windows-result" version = "0.4.1" @@ -4592,6 +8106,15 @@ dependencies = [ "windows_x86_64_msvc 0.53.1", ] +[[package]] +name = "windows-threading" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" +dependencies = [ + "windows-link", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -4727,6 +8250,60 @@ dependencies = [ "tap", ] +[[package]] +name = "x25519-dalek" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" +dependencies = [ + "curve25519-dalek", + "rand_core 0.6.4", + "serde", + "zeroize", +] + +[[package]] +name = "x509-parser" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4569f339c0c402346d4a75a9e39cf8dad310e287eef1ff56d4c68e5067f53460" +dependencies = [ + "asn1-rs", + "data-encoding", + "der-parser", + "lazy_static", + "nom 7.1.3", + "oid-registry", + "rusticata-macros", + "thiserror 2.0.18", + "time", +] + +[[package]] +name = "xattr" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +dependencies = [ + "libc", + "rustix", +] + +[[package]] +name = "xml-rs" +version = "0.8.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f" + +[[package]] +name = "xmltree" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7d8a75eaf6557bb84a65ace8609883db44a29951042ada9b393151532e41fcb" +dependencies = [ + "xml-rs", +] + [[package]] name = "yaml-rust2" version = "0.10.4" @@ -4735,7 +8312,16 @@ checksum = "2462ea039c445496d8793d052e13787f2b90e750b833afee748e601c17621ed9" dependencies = [ "arraydeque", "encoding_rs", - "hashlink", + "hashlink 0.10.0", +] + +[[package]] +name = "yasna" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +dependencies = [ + "time", ] [[package]] diff --git a/docs/privacy-test-matrix.md b/docs/privacy-test-matrix.md new file mode 100644 index 0000000..da24050 --- /dev/null +++ b/docs/privacy-test-matrix.md @@ -0,0 +1,337 @@ +# Privacy test matrix (Q2 privacy validation) + +Living tracker for the Q2 privacy-feature validation commitment: add privacy-preserving +variants of the existing `token` / `ata` / `amm` / `stablecoin` integration test flows, and +record which combinations work, fail, or cannot be expressed. Every row starting in +**Not started** should end the effort as **Pass** (test merged) or **Fail** / +**Not-expressible** (folded into `docs/privacy-gap-report.md` with root cause). + +This is the tracking scaffold, not the final deliverable — `docs/privacy-gap-report.md` gets +written from the resolved state of this table. + +## Legend + +**Dimension** — which cross-cutting Q2 feature (or baseline coverage gap) a row exercises: + +| Code | Meaning | +|---|---| +| `BASE` | Extends the already-proven single-private-account pattern (shield / private→private / deshield) to an instruction that has no private coverage yet. Not itself one of the four Q2 checkboxes. | +| `PDA` | Private PDAs used as program inputs | +| `GROUP` | Sharing a private account (group-owned) used as a program account | +| `EXIST` | Sending funds to an existing private account (not a fresh one) | +| `CHAIN` | Multiple private accounts in one transaction, and/or a private account carried through a `ChainedCall` | + +**Priority** — `P1` build first, `P2` second wave, `P3` stretch/optional. + +**Status** — `Not started` / `Pass` / `Fail` / `Not-expressible` / `Blocked`. + +**Depends on** — which other deployed program(s) or new crate dependencies the row needs. + +--- + +## Token (`token.rs`) — no program dependencies + +Foundation layer. Has no PDAs of its own and issues no `ChainedCall`s, so `PDA` and `CHAIN` +don't apply here — it's the substrate the other three programs build on. + +### Cross-cutting checkbox audit (end of Token phase, 2026-07-07) + +Checked against the 4 Q2 checkboxes explicitly, not assumed: + +| Checkbox | Status | Basis | +|---|---|---| +| Private PDAs used as program inputs | **N/A at this layer** | `token_core` has no `for_public_pda`/`for_private_pda` calls anywhere — Token holdings are addressed by arbitrary `AccountId`, not program-derived. Only testable once wrapped by another program's PDA (ATA/AMM/Stablecoin) — correctly deferred, not a gap in Token coverage. | +| Sharing a private account (group-owned) | **Covered** | `token_group_owned_holding_shared_control` — see finding below. | +| Sending funds to an existing private account | **Covered** | `token_transfer_into_existing_private_holding` — see finding above. | +| Multiple private accounts in one tx / private accounts through chained calls | **Partially covered** | "Multiple private accounts in one tx" half: covered, but by the *pre-existing* `token_private_transfer` (two private legs, zero public), not by anything added this phase — none of the new tests this phase have more than one private leg. "Carried through chained calls" half: N/A at this layer, Token issues no `ChainedCall`s (only ATA/AMM/Stablecoin do); deferred. | + +Net: of the 4 checkboxes, Token-phase work directly validated 2 (`EXIST`, `GROUP`), leaned on a +pre-existing test for half of a 3rd (`CHAIN`'s multi-account half), and the remaining checkbox +(`PDA`) plus the other half of `CHAIN` are structurally out of reach until ATA/AMM/Stablecoin +phases — not oversights specific to this phase. + +### Existing + +| Instruction | Dimension | Test | Status | +|---|---|---|---| +| Transfer | BASE (shield) | `token_shielded_transfer` | Pass | +| Transfer | BASE (private→private) | `token_private_transfer` | Pass | +| Transfer | BASE (deshield) | `token_deshielded_transfer` | Pass | +| Transfer | BASE (authorized variant) | `token_shielded_transfer_authorized_private_init` — fresh recipient self-initializes via `PrivateAuthorizedInit` instead of being passively credited via `PrivateUnauthorized` | Pass | +| Mint | BASE | `token_mint_shielded` — mint directly to a fresh private recipient (self-authority signer + `PrivateUnauthorized` recipient) | Pass | +| Mint | BASE (authorized variant) | `token_mint_authorized_init` — mint to a fresh recipient that self-initializes via `PrivateAuthorizedInit` (own `nsk` supplied) instead of being passively credited | Pass | +| Burn | BASE | `token_private_burn` — burn from an existing private holding via a single `PrivateAuthorizedUpdate` | Pass | +| Transfer | `EXIST` | `token_transfer_into_existing_private_holding` — second transfer into an already-shielded recipient | Pass — **with a finding**, see below | +| Transfer | `EXIST` + `CHAIN` (fully private) | `token_private_transfer_into_existing_private_holding` — both legs private, recipient already existing (not fresh); two distinct accounts both via `PrivateAuthorizedUpdate` in one tx | Pass | +| InitializeAccount | BASE | `token_initialize_private_account` — self-init of a private holding via `PrivateAuthorizedInit` | Pass | +| InitializeAccount | new: self-service-only boundary | `token_initialize_private_account_without_nsk_is_not_expressible` | **Not-expressible — confirmed by design, not a gap** | +| Transfer + Burn | `GROUP` | `token_group_owned_holding_shared_control` — shield into a GMS-derived shared holding, spend from it via an independently-derived key | Pass | +| Mint | `EXIST` | `token_mint_into_existing_private_holding` — mint once to establish the holding, mint again into it via `PrivateAuthorizedUpdate` | Pass | + +**Finding (`GROUP`, confirmed 2026-07-07):** sharing a private account genuinely works, and the test +was built to prove *sharing*, not just code reuse: "Alice" creates a `GroupKeyHolder` (fresh GMS) +and derives the shared account's npk/vpk via `derive_keys_for_shared_account`; she shields tokens +into it. The GMS is then distributed to "Bob" through the real `seal_for`/`unseal` ML-KEM-768 +handshake — Bob never touches Alice's `GroupKeyHolder` object, only the sealed bytes. Bob +independently re-derives the identical nsk/npk from the unsealed GMS and successfully burns from +the shared holding using his own derivation. Required adding `key_protocol` as a new git dependency +(same repo/tag as `nssa`/`nssa_core`) to `integration_tests/Cargo.toml` — it wasn't previously a +dependency of `lez-programs`. Passed on the first attempt; no gap found for this dimension at the +Token layer. + +**Finding (`EXIST`, confirmed 2026-07-07):** crediting an *existing* private account works, but only if the +recipient cooperates in the same transaction. Confirmed directly against `InputAccountIdentity`'s +doc comments and `output.rs` in `lee_core`: every variant that touches an existing private account +(`PrivateAuthorizedUpdate`, `PrivatePdaUpdate`) requires that account's own `nsk` + a membership +proof. There is no "blind credit" variant analogous to how any public account can be unilaterally +credited — a sender cannot push funds into an existing private account without the recipient +actively co-signing (supplying their nsk) in that same transaction. This is a real protocol/UX +property, not a bug: worth flagging to the privacy work as the answer to "can you send to an +existing private account" being **yes, but only cooperatively**, which has real wallet-UX +implications (recipient must be online / pre-coordinate, unlike a public transfer or a fresh +shield). + +**Finding (`token_private_transfer_into_existing_private_holding`, confirmed 2026-07-07):** +fills the last open combination for Transfer — every prior private test had at most one +existing-and-private leg (`token_transfer_into_existing_private_holding`'s recipient) or a +fresh second leg (`token_private_transfer`'s recipient), never both legs private *and* the +recipient already existing. Two distinct private accounts, each independently proven via its +own `PrivateAuthorizedUpdate` (one spending, one crediting an existing balance), compose in a +single transaction with no public account anywhere — no signer, no public message ids at all. +Passed on the first attempt; built entirely on direct seeding (`with_private_accounts`) for +both sides, no real setup transactions needed. + +**Finding (`token_mint_into_existing_private_holding`, confirmed 2026-07-07):** the `EXIST` +cooperation requirement generalizes across instructions, not just Transfer. `mint_inner` +already supports crediting an existing holding on the public side (branches on +`user_holding_account.account == Account::default()`); the private side needs the same +`PrivateAuthorizedUpdate` cooperation as Transfer — no instruction-specific escape hatch. +Passed on the first attempt once modeled on `token_transfer_into_existing_private_holding`. + +### Planned + +| Instruction | Dimension | Test | Priority | Depends on | Status | +|---|---|---|---|---|---| +| MintWithAuthority | BASE | `token_mint_with_authority_to_private_holding` | P3 | — | Not started | +| NewFungibleDefinition, NewDefinitionWithMetadata, SetAuthority(WithAuthority), PrintNft | — | **Not planned** — these operate on canonical, publicly-resolvable definitions/authorities; a "private token definition" has no coherent meaning since holders/traders must resolve it | — | — | Out of scope | + +**Correction (`token_initialize_private_account`, resolved 2026-07-07):** originally flagged as a +plausible `Not-expressible` case because `initialize.rs` hard-asserts `is_authorized == true` while +a fresh account created via `PrivateUnauthorized` must be `false`. That flag was based on picking +the wrong identity variant, not a real protocol limit. `InitializeAccount`'s guest requires the +target to be a *signer* (`#[account(init, signer)]`) — i.e. self-initialization, the same shape as +`PrivateAuthorizedInit` (owner supplies their own `nsk` directly, `is_authorized: true` is +legitimate), not `PrivateUnauthorized` (third party credits an account they don't control, `nsk` +withheld, `is_authorized` must be `false`). Matching the identity variant to the instruction's +actual authorization shape resolved it cleanly — passed on the first attempt once corrected. + +**Finding (self-service-only boundary, confirmed 2026-07-07 — prompted by a direct question, +not originally in the matrix):** can a third party initialize a private Token holding for an +`(npk, vpk, identifier)` whose `nsk` they don't possess? No — and this is a deliberate design +boundary, not a gap. Unlike `Transfer`/`Mint`, whose recipient-side host logic never asserts +`is_authorized` (which is exactly why third-party shielding into a fresh recipient works there +via `PrivateUnauthorized`), `InitializeAccount`'s guest declares `account_to_initialize` as +`#[account(init, signer)]`. Attempting it via `PrivateUnauthorized` (`is_authorized: false`, +no `nsk` needed) is rejected — empirically confirmed — at the SPEL macro's own account +validation layer ("`must be a signer`"), before `token_program::initialize::initialize_account`'s +own `is_authorized` assert is even reached. The only variant that can construct a fresh private +account here is `PrivateAuthorizedInit`, which requires supplying `nsk` directly. Net: this +instruction is self-service-only by construction — you can initialize your own private holding, +but not one on someone else's behalf without their key material. Worth carrying into the gap +report as a scoping note on `EXIST`/`BASE`, not a defect. + +**Finding (`token_mint_authorized_init`, confirmed 2026-07-07):** the self-service-only +boundary above is specific to `InitializeAccount`, not a general rule about "authorized" private +identities. `Mint`'s guest marks `user_holding_account` as `#[account(mut)]` only (no +`signer`), and `mint_inner` never asserts `is_authorized` on it — confirmed by reading +`token/src/mint.rs` before writing the test, then verified empirically. So minting to a +recipient that self-initializes via `PrivateAuthorizedInit` (their own `nsk` supplied) works +just as well as `token_mint_shielded`'s passive `PrivateUnauthorized` recipient — passed on the +first attempt. Worth stating plainly in the gap report: whether a "self-authorized fresh +recipient" is accepted is instruction-specific (gated by that instruction's own signer +requirement), not a blanket protocol rule. + +**Finding (`token_shielded_transfer_authorized_private_init`, confirmed 2026-07-07):** the same +`PrivateAuthorizedInit`-instead-of-`PrivateUnauthorized` variant generalizes to `Transfer` too, +closing the last instruction where every fresh-recipient test used only `PrivateUnauthorized` +(`token_shielded_transfer`, `token_private_transfer`'s new recipient, the group test's shield +step). `transfer.rs` asserts `is_authorized` only on the sender, never the recipient — same +shape as `Mint` — so this was expected and passed on the first attempt. Between this and the +`Mint`/`InitializeAccount` results, the picture is now complete: whether a fresh recipient can +choose to self-initialize (`PrivateAuthorizedInit`) instead of being passively credited +(`PrivateUnauthorized`) depends entirely on whether that instruction's guest marks the target +as a signer — true for `InitializeAccount` only (where `PrivateUnauthorized` is actually +rejected), optional for `Transfer`/`Mint` (both variants accepted). + +--- + +## ATA (`ata.rs`) — depends on Token + +### Existing + +| Instruction | Dimension | Test | Status | +|---|---|---|---| +| Create | BASE (private owner only; ATA account + definition public) | `ata_create_from_private_owner` | Pass | +| Create | `PDA` | `ata_create_private_ata_holding_is_not_expressible` | **Not-expressible — confirmed** | + +Verified in `ata/src/create.rs`: the owner account is **not** forwarded into the +`ChainedCall` to Token — only `token_definition` and the ATA holding are. So the existing +`ata_create_from_private_owner` test proves a private account can seed a PDA derivation and +appear as a top-level tx participant, but does **not** prove a private account traveling +through a chained call. That gap is still open despite appearances. + +**Finding (`PDA`, confirmed 2026-07-07 — root cause, not just an observation):** the ATA +holding can never be made a private account as ATA is currently coded, and this is a +structural fact provable from `lee_core`'s circuit source, not empirical friction. Traced +precisely: `Create`'s `ChainedCall.pda_seeds` authorizes Token to mutate +`for_public_pda(ata_program_id, seed)` — a match under the *public* PDA formula. In +`resolve_authorization_and_record_bindings` (`execution_state.rs`), a caller-seed match only +gets recorded into `private_pda_bound_positions` when it matches under `for_private_pda` +(`is_private_form == true`) — a public-form match authorizes the account but never binds it +as a private PDA. Every `PrivatePdaInit`/`PrivatePdaUpdate` identity requires its position to +appear in that binding map (hard `assert!` at `execution_state.rs:211`), and ATA's own +`verify_ata_and_get_seed` independently requires the account id to equal +`for_public_pda(ata_program_id, seed)` — never `for_private_pda`'s output, by construction of +two different hash domains. These two requirements are mutually exclusive for the same +account_id, full stop — confirmed empirically by attempting exactly this and getting the +precise, deterministic rejection (`ata_create_private_ata_holding_is_not_expressible`, which +asserts on the exact panic text). +**This generalizes**: AMM's vault/pool and Stablecoin's position/vault use the identical +`for_public_pda`-only derivation, so they will hit the *same* wall for the *same* reason — no +need to rediscover this per program, just confirm each one uses `for_public_pda` (already +verified for both in `amm_core`/`stablecoin_core`) and cite this finding. **The only fix** is a +source change to `ata_core`/`amm_core`/`stablecoin_core` to derive PDAs via `for_private_pda` +instead — out of scope for this test-writing task, but this is the single clearest, most +actionable item to feed back to the privacy/protocol work. + +All originally-planned ATA rows are now resolved — see updated `Existing` table below. ATA phase +is complete. + +| Instruction | Dimension | Test | Status | +|---|---|---|---| +| Transfer | `CHAIN` + `EXIST` (collapsed — see finding) | `ata_transfer_to_existing_private_recipient` | Pass | +| Burn | new: signer-authorization | `ata_burn_with_private_owner_signing` | Pass | +| Burn | `GROUP` + signer-authorization | `ata_group_owned_owner_signing` | Pass | + +**Finding (`CHAIN` + `EXIST`, confirmed 2026-07-07):** `ata_program::transfer::transfer_from_associated_token_account` +hard-asserts `recipient.account != Account::default()` ("Recipient token holding must be +initialized"). That means a *fresh* private recipient (shield-style, `PrivateUnauthorized`) can +never be created through `ATA::Transfer` — only an already-existing account can be credited. +This collapses what the matrix originally planned as two separate rows (`BASE` and `EXIST`) +into one: `ata_transfer_to_existing_private_recipient` funds a private holding via a direct +(non-ATA) `Token::Transfer` shield first, then sends more into it through ATA's chained call, +with the recipient cooperating via `PrivateAuthorizedUpdate` (consistent with the Token-phase +`EXIST` finding). This is also the first test in the whole exercise where a private account +identity travels through a *nested* `ChainedCall` rather than a top-level instruction call — +and it worked on the first attempt, with no special handling needed. + +**Finding (signer-authorization, confirmed 2026-07-07 — new angle, not in the original matrix):** +`Transfer`/`Burn` require `owner` to be a *signer* (`#[account(signer)]`), unlike `Create` +(merely `mut`). Every existing private-owner test only used owner passively (`Create`, no +signer requirement). `ata_burn_with_private_owner_signing` tests whether a private account can +satisfy a signer requirement by self-initializing *and* signing in the same transaction via +`PrivateAuthorizedInit` — it does, cleanly, on the first attempt. `ata_group_owned_owner_signing` +composes this with `GROUP`: the GMS is distributed through the real seal/unseal handshake (as +in `token_group_owned_holding_shared_control`), and "Bob" — who never touches Alice's +`GroupKeyHolder` object — independently re-derives the matching nsk/npk and signs. Both pass. +Worth feeding back as a positive finding: private/shared accounts can serve as full signing +authorities for instructions that require it, not just as passive recipients. + +--- + +## AMM (`amm.rs`) — depends on Token, TWAP oracle + +33 public tests, 0 private. Confirmed in `amm_core`: all 5 PDAs (config, pool, vault×2, +liquidity-token, lp-lock) use `for_public_pda` exclusively. + +Not every account is an equally meaningful privacy target: Pool/Config are the AMM's public +price surface (reserves must be readable to quote a swap; TWAP needs a continuously +observable tick) — privatizing them fights the AMM's purpose. Vault/LP-lock are the credible +middle case. User-held token/LP balances are the highest-value target. + +### Existing + +0 private tests out of 33 public. + +### Planned + +| Instruction | Dimension | Test | Priority | Depends on | Status | +|---|---|---|---|---|---| +| SwapExactInput | `CHAIN` | `amm_swap_a_to_b_private_user_holding` | P1 | Token, TWAP oracle (public leg) | Not started | +| SwapExactOutput | `CHAIN` | `amm_swap_exact_output_private_user_holding` | P1 | Token, TWAP oracle (public leg) | Not started | +| AddLiquidity | `CHAIN` | `amm_add_liquidity_private_user_holdings` | P1 | Token, TWAP oracle (public leg) | Not started | +| AddLiquidity | BASE | `amm_add_liquidity_private_lp_holding` — private LP output holding | P1 | Token | Not started | +| RemoveLiquidity | `CHAIN` | `amm_remove_liquidity_private_lp_holding` | P1 | Token, TWAP oracle (public leg) | Not started | +| Swap / AddLiquidity | `EXIST` | `amm_swap_into_existing_private_holding` | P2 | Token | Not started | +| NewDefinition | BASE | `amm_new_definition_private_initial_lp_holder` | P2 | Token | Not started | +| Swap / AddLiquidity (vault) | `PDA` | `amm_swap_with_private_vault_pda` — predicted **not-expressible** per the ATA `PDA` finding (same `for_public_pda`-only root cause, confirmed in `amm_core`); write as a quick confirmation citing that finding, not a fresh investigation | P2 | Token | Not started | +| AddLiquidity / RemoveLiquidity | `GROUP` | `amm_group_owned_lp_holding` | P3 | Token, `key_protocol` | Not started | +| Pool/Config (any) | `PDA` | `amm_attempt_private_pool_pda` — same predicted not-expressible outcome as above; low priority given the vault row already confirms the root cause for this program | P3 | Token | Not started | +| Initialize, UpdateConfig, CreatePriceObservations, CreateOraclePriceAccount, SyncReserves | — | **Not planned** — admin/infra instructions over public protocol state; a private admin authority is legitimate but low value | — | — | Out of scope (for now) | + +Note: every Swap/AddLiquidity/RemoveLiquidity chains to *both* Token (transfers) and TWAP +oracle (tick refresh) in one instruction — so every `CHAIN` row above is automatically also +a "some legs private, some public" test. Call that out explicitly when the test is written, +not as an incidental detail. + +--- + +## Stablecoin (`stablecoin.rs`) — depends on Token + +Only 2 tests total today (`stablecoin_open_position_then_withdraw_collateral`, +`stablecoin_repay_debt_burns_stablecoins_and_decreases_debt`), 0 private. Both PDAs +(position, position vault) are `for_public_pda` only. + +Arguably the most naturally privacy-motivated program of the four — a CDP's collateral/debt +is exactly what a user would want hidden — despite having the thinnest existing baseline. + +### Existing + +0 private tests out of 2 public. + +### Planned + +| Instruction | Dimension | Test | Priority | Depends on | Status | +|---|---|---|---|---|---| +| OpenPosition | `CHAIN` | `stablecoin_open_position_private_collateral_holding` | P1 | Token | Not started | +| WithdrawCollateral | `CHAIN` | `stablecoin_withdraw_collateral_private_holding` | P1 | Token | Not started | +| RepayDebt | `CHAIN` | `stablecoin_repay_debt_private_holding` | P1 | Token | Not started | +| OpenPosition / Position + Vault | `PDA` | `stablecoin_open_position_private_pda` — predicted **not-expressible** per the ATA `PDA` finding (same `for_public_pda`-only root cause, confirmed in `stablecoin_core`); still worth writing as the clearest real-world case (a CDP position is the most natural thing to want private of anything in this whole exercise), but as a confirmation citing the root cause, not a fresh investigation | P1 (high value as *documentation* of the clearest case, even though the outcome is now predicted) | Token | Not started | +| OpenPosition / WithdrawCollateral | `EXIST` | `stablecoin_deposit_into_existing_private_holding` | P2 | Token | Not started | +| OpenPosition (joint CDP) | `GROUP` | `stablecoin_group_owned_position` | P3 | Token, `key_protocol` | Not started | +| (ProtocolParameters, any) | — | **Not planned** — not yet consumed by any instruction (no freeze/admin logic wired up); nothing to test | — | — | Out of scope | + +--- + +## Phase 0 prerequisites (blocking every remaining `GROUP` row) + +- ~~Add `key_protocol` as a git dependency~~ — **done** (2026-07-07), added to + `integration_tests/Cargo.toml` pinned to the same repo/tag as `nssa`/`nssa_core`. Unblocks the + remaining `GROUP` rows in ATA/AMM/Stablecoin; each still needs its own program-specific test + (PDA-based group ownership, not just the regular-account path proven for Token). +- Build the shared privacy test kit in `integration_tests/src/lib.rs` (shield / spend / + private-PDA fund-spend / group-derive helpers) — still not done. Tests so far (Token and ATA + phases) are still hand-rolled per-file; revisit whether to extract shared helpers before AMM. + +**Implementation technique worth carrying into AMM/Stablecoin (found 2026-07-07):** private +account preconditions don't need a real proven transaction to set up. `V03State::with_private_accounts(impl IntoIterator)` +is a genuine, non-test-gated builder method — pair `Commitment::new(&id, &account)` with +`Nullifier::for_account_initialization(&id)` (the same pairing a real `PrivateUnauthorized`/ +`PrivateAuthorizedInit` would have produced) and the seeded state is indistinguishable from a +real one to any subsequent transaction. Confirmed against `lee`'s own test suite pattern before +using it, then applied to refactor `token_private_burn`, `token_transfer_into_existing_private_holding`, +and `token_mint_into_existing_private_holding`'s setup legs — all still pass. Caveat: seeding +skips whatever *public*-side effect the bypassed transaction would have had (sender debit for a +shield, supply increase for a mint) — assertions on public state must account for that, matching +how public fixtures (`Accounts::holder_init()`) already set balances without a real mint ever +having produced them. This will matter more for AMM/Stablecoin, where setup transactions are +heavier (chained calls, multiple accounts) than a single shield. + +## Row count summary + +| Program | Existing private / confirmed | Planned rows | Out-of-scope instructions noted | +|---|---|---|---| +| Token | 13 (3 pre-existing + 10 new: 9 pass + 1 confirmed not-expressible by design) | 1 | 5 | +| ATA | 5 (4 pass + 1 confirmed not-expressible — phase complete) | 0 | 0 | +| AMM | 0 (2 rows now predicted not-expressible pending confirmation) | 10 | 5 | +| Stablecoin | 0 | 6 | 1 | diff --git a/programs/integration_tests/Cargo.toml b/programs/integration_tests/Cargo.toml index ce1e5de..9eb2b10 100644 --- a/programs/integration_tests/Cargo.toml +++ b/programs/integration_tests/Cargo.toml @@ -10,6 +10,7 @@ workspace = true nssa = { workspace = true } nssa_core = { workspace = true, features = ["host", "test_utils"] } clock_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.2.0-rc6" } +key_protocol = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.2.0-rc6" } amm_core = { workspace = true } token_core = { workspace = true } ata_core = { workspace = true } diff --git a/programs/integration_tests/tests/ata.rs b/programs/integration_tests/tests/ata.rs index 6e5d016..99df64e 100644 --- a/programs/integration_tests/tests/ata.rs +++ b/programs/integration_tests/tests/ata.rs @@ -1,6 +1,10 @@ use std::collections::HashMap; use ata_core::{compute_ata_seed, get_associated_token_account_id}; +use key_protocol::key_management::{ + group_key_holder::{GroupKeyHolder, SealingPublicKey}, + secret_holders::SecretSpendingKey, +}; use nssa::{ execute_and_prove, privacy_preserving_transaction::{ @@ -13,7 +17,7 @@ use nssa::{ use nssa_core::{ account::{Account, AccountId, AccountWithMetadata, Data, Nonce}, encryption::{EphemeralPublicKey, ViewingPublicKey}, - EncryptedAccountData, InputAccountIdentity, NullifierPublicKey, NullifierSecretKey, + Commitment, EncryptedAccountData, InputAccountIdentity, NullifierPublicKey, NullifierSecretKey, }; use token_core::{TokenDefinition, TokenHolding}; @@ -592,3 +596,537 @@ fn ata_create_from_private_owner() { } ); } + +// Marvin-todo +/// Documents a confirmed protocol gap (`PDA` Q2 dimension): the ATA holding can never be made +/// a private account as ATA is currently coded. `Create`'s `ChainedCall.pda_seeds` authorizes +/// Token to mutate `for_public_pda(ata_program_id, seed)` — a *public*-form PDA match. Per +/// `resolve_authorization_and_record_bindings` in `lee_core`'s `execution_state.rs`, a +/// caller-seed match only gets recorded in `private_pda_bound_positions` when it matches under +/// `for_private_pda` (`is_private_form == true`); a public-form match authorizes the account +/// but never binds it as a private PDA. Since `PrivatePdaInit`/`PrivatePdaUpdate` require their +/// position to appear in that binding map (`execution_state.rs:211`), and ATA's own +/// `verify_ata_and_get_seed` independently requires the account id to equal +/// `for_public_pda(ata_program_id, seed)` (never `for_private_pda`'s output, by construction), +/// these two requirements can never both hold for the same account_id. This is not +/// program-specific friction — it's structural: fixing it would require `ata_core` (and +/// equally amm_core / stablecoin_core) to derive their PDAs via `for_private_pda` instead, +/// which is a source change to the program, not a test workaround. +#[test] +fn ata_create_private_ata_holding_is_not_expressible() { + let mut state = V03State::new(); + deploy_programs(&mut state); + state.force_insert_account(Ids::token_definition(), Accounts::token_definition_init()); + + let owner_id = Ids::owner(); + let owner_account = state.get_account_by_id(owner_id); + + // Fresh personal npk/vpk for the ATA holding's privacy identity — distinct from the + // owner's plain public keypair, which only supplies the seed input. + let ata_nsk: NullifierSecretKey = [21u8; 32]; + let ata_npk = NullifierPublicKey::from(&ata_nsk); + let ata_vpk = ViewingPublicKey::from_seed(&[41u8; 32], &[42u8; 32]); + + // Address stays the *standard* public-PDA formula ATA always uses — only its state + // privacy is under test, not its address derivation. + let seed = compute_ata_seed(Ids::token_program(), owner_id, Ids::token_definition()); + let ata_id = get_associated_token_account_id(&Ids::ata_program(), &seed); + + let owner_pre = AccountWithMetadata::new(owner_account, true, owner_id); + let def_pre = AccountWithMetadata::new( + Accounts::token_definition_init(), + false, + Ids::token_definition(), + ); + let ata_pre = AccountWithMetadata::new(Account::default(), false, ata_id); + + let instruction = ata_core::Instruction::Create { + token_program_id: Ids::token_program(), + }; + let instruction_data = Program::serialize_instruction(instruction).unwrap(); + + let shared_secret = SharedSecretKey::encapsulate_deterministic(&ata_vpk, &[0u8; 32], 0).0; + + let ata_program = Program::new(ata_methods::ATA_ELF.to_vec().into()).unwrap(); + let token_program = Program::new(token_methods::TOKEN_ELF.to_vec().into()).unwrap(); + let program_with_deps = ProgramWithDependencies::new( + ata_program, + HashMap::from([(Ids::token_program(), token_program)]), + ); + + let result = execute_and_prove( + vec![owner_pre, def_pre, ata_pre], + instruction_data, + vec![ + InputAccountIdentity::Public, + InputAccountIdentity::Public, + InputAccountIdentity::PrivatePdaInit { + epk: EphemeralPublicKey(Vec::new()), + view_tag: EncryptedAccountData::compute_view_tag(&ata_npk, &ata_vpk), + npk: ata_npk, + ssk: shared_secret, + identifier: 0, + seed: None, + }, + ], + &program_with_deps, + ); + + let err = result.expect_err( + "a private-PDA ATA holding must be rejected: its account id can never satisfy both \ + ATA's own for_public_pda address check and PrivatePdaInit's for_private_pda binding \ + requirement simultaneously", + ); + let message = format!("{err:?}"); + assert!( + message.contains("has no proven (seed, npk) binding via Claim::Pda or caller pda_seeds"), + "expected the private-PDA binding rejection, got a different error: {message}" + ); +} + +// Marvin-todo +/// Credits an *already-existing* private holding through ATA's chained call to Token, and +/// documents a structural finding along the way: +/// `ata_program::transfer::transfer_from_associated_token_account` hard-asserts `recipient.account +/// != Account::default()` ("Recipient token holding must be initialized"), so a *fresh* private +/// recipient (shield-style, `PrivateUnauthorized`) can never be created through `ATA::Transfer` — +/// only an existing account can be credited. That collapses what would otherwise be separate `BASE` +/// and `EXIST` tests into one: this test necessarily exercises both "private account through a +/// chained call" (`CHAIN`) and "sending to an existing private account" (`EXIST`, requiring the +/// recipient's cooperation via `PrivateAuthorizedUpdate`, per the finding already confirmed in +/// `token.rs`). +/// +/// The private holding is funded beforehand via a direct (non-ATA) `Token::Transfer` shield +/// from a throwaway public holder, since neither `ATA::Transfer` (blocked by the assert above) +/// nor `Token::Mint` (this test fixture's definition has `authority: None`, fixed supply) can +/// create it. +#[test] +fn ata_transfer_to_existing_private_recipient() { + let mut state = state_for_ata_tests(); + + // A throwaway public holder to shield from directly via Token — bypassing ATA entirely, + // since ATA::Transfer cannot originate a fresh private recipient (see doc comment above). + let shield_source_key = PrivateKey::try_new([77u8; 32]).expect("valid private key"); + let shield_source_id = AccountId::from(&PublicKey::new_from_private_key(&shield_source_key)); + state.force_insert_account( + shield_source_id, + Account { + program_owner: Ids::token_program(), + balance: 0_u128, + data: Data::from(&TokenHolding::Fungible { + definition_id: Ids::token_definition(), + balance: 1_000_000_u128, + }), + nonce: Nonce(0), + }, + ); + + let recipient_nsk: NullifierSecretKey = [51u8; 32]; + let recipient_npk = NullifierPublicKey::from(&recipient_nsk); + let recipient_vpk = ViewingPublicKey::from_seed(&[61u8; 32], &[62u8; 32]); + let recipient_id = AccountId::for_regular_private_account(&recipient_npk, 0); + + let shield_amount = 500_000_u128; + let source_pre = AccountWithMetadata::new( + state.get_account_by_id(shield_source_id), + true, + shield_source_id, + ); + let fresh_recipient_pre = AccountWithMetadata::new(Account::default(), false, recipient_id); + let shield_secret = SharedSecretKey::encapsulate_deterministic(&recipient_vpk, &[0u8; 32], 0).0; + + let token_program_for_shield = Program::new(token_methods::TOKEN_ELF.to_vec().into()) + .expect("valid token ELF") + .into(); + let (shield_output, shield_proof) = execute_and_prove( + vec![source_pre, fresh_recipient_pre], + Program::serialize_instruction(token_core::Instruction::Transfer { + amount_to_transfer: shield_amount, + }) + .unwrap(), + vec![ + InputAccountIdentity::Public, + InputAccountIdentity::PrivateUnauthorized { + epk: EphemeralPublicKey(Vec::new()), + view_tag: EncryptedAccountData::compute_view_tag(&recipient_npk, &recipient_vpk), + npk: recipient_npk, + ssk: shield_secret, + identifier: 0, + }, + ], + &token_program_for_shield, + ) + .unwrap(); + let shield_message = + Message::try_from_circuit_output(vec![shield_source_id], vec![Nonce(0)], shield_output) + .unwrap(); + let shield_witness = + WitnessSet::for_message(&shield_message, shield_proof, &[&shield_source_key]); + state + .transition_from_privacy_preserving_transaction( + &PrivacyPreservingTransaction::new(shield_message, shield_witness), + 0, + 0, + ) + .unwrap(); + + let recipient_after_shield = Account { + program_owner: Ids::token_program(), + balance: 0_u128, + data: Data::from(&TokenHolding::Fungible { + definition_id: Ids::token_definition(), + balance: shield_amount, + }), + nonce: Nonce::private_account_nonce_init(&recipient_id), + }; + assert!( + state + .get_proof_for_commitment(&Commitment::new(&recipient_id, &recipient_after_shield)) + .is_some(), + "shield setup must land before the ATA transfer under test" + ); + + // Now the actual test: owner's ATA sends more into that now-existing private recipient. + let owner_id = Ids::owner(); + let owner_account = state.get_account_by_id(owner_id); + let sender_ata_id = Ids::owner_ata(); + let sender_ata_account = state.get_account_by_id(sender_ata_id); + + let membership_proof = state + .get_proof_for_commitment(&Commitment::new(&recipient_id, &recipient_after_shield)) + .expect("recipient's commitment must be in the set"); + let transfer_secret = + SharedSecretKey::encapsulate_deterministic(&recipient_vpk, &[0u8; 32], 0).0; + + let owner_pre = AccountWithMetadata::new(owner_account, true, owner_id); + let sender_ata_pre = AccountWithMetadata::new(sender_ata_account, false, sender_ata_id); + let recipient_pre = + AccountWithMetadata::new(recipient_after_shield.clone(), true, recipient_id); + + let ata_transfer_amount = 200_000_u128; + let instruction = ata_core::Instruction::Transfer { + token_program_id: Ids::token_program(), + amount: ata_transfer_amount, + }; + let ata_program = Program::new(ata_methods::ATA_ELF.to_vec().into()).unwrap(); + let token_program = Program::new(token_methods::TOKEN_ELF.to_vec().into()).unwrap(); + let program_with_deps = ProgramWithDependencies::new( + ata_program, + HashMap::from([(Ids::token_program(), token_program)]), + ); + + let (output, proof) = execute_and_prove( + vec![owner_pre, sender_ata_pre, recipient_pre], + Program::serialize_instruction(instruction).unwrap(), + vec![ + InputAccountIdentity::Public, + InputAccountIdentity::Public, + InputAccountIdentity::PrivateAuthorizedUpdate { + epk: EphemeralPublicKey(Vec::new()), + view_tag: EncryptedAccountData::compute_view_tag(&recipient_npk, &recipient_vpk), + ssk: transfer_secret, + nsk: recipient_nsk, + membership_proof, + identifier: 0, + }, + ], + &program_with_deps, + ) + .unwrap(); + + let message = + Message::try_from_circuit_output(vec![owner_id, sender_ata_id], vec![Nonce(0)], output) + .unwrap(); + let witness_set = WitnessSet::for_message(&message, proof, &[&Keys::owner_key()]); + state + .transition_from_privacy_preserving_transaction( + &PrivacyPreservingTransaction::new(message, witness_set), + 0, + 0, + ) + .unwrap(); + + assert_eq!( + state.get_account_by_id(sender_ata_id), + Account { + program_owner: Ids::token_program(), + balance: 0_u128, + data: Data::from(&TokenHolding::Fungible { + definition_id: Ids::token_definition(), + balance: 1_000_000_u128 - ata_transfer_amount, + }), + nonce: Nonce(0), + } + ); + + let recipient_nonce_after = Nonce::private_account_nonce_init(&recipient_id) + .private_account_nonce_increment(&recipient_nsk); + let recipient_after_ata_transfer = Account { + program_owner: Ids::token_program(), + balance: 0_u128, + data: Data::from(&TokenHolding::Fungible { + definition_id: Ids::token_definition(), + balance: shield_amount + ata_transfer_amount, + }), + nonce: recipient_nonce_after, + }; + assert!(state + .get_proof_for_commitment(&Commitment::new( + &recipient_id, + &recipient_after_ata_transfer + )) + .is_some()); +} + +// Marvin-todo +/// Tests a previously-untried combination: `Burn`'s guest requires `owner` to be a *signer* +/// (`#[account(signer)]`) — every existing private-owner test so far +/// (`ata_create_from_private_owner`) only used owner as a passive `PrivateUnauthorized` recipient +/// in `Create`, which doesn't need signer authorization at all. Here, owner self-initializes *and* +/// signs in the same transaction via `PrivateAuthorizedInit` (proving control by supplying their +/// own nsk directly) — the ATA holding itself stays public, per the confirmed `PDA` finding above; +/// only the signing identity is private. +#[test] +fn ata_burn_with_private_owner_signing() { + let mut state = V03State::new(); + deploy_programs(&mut state); + state.force_insert_account(Ids::token_definition(), Accounts::token_definition_init()); + + let owner_nsk: NullifierSecretKey = [91u8; 32]; + let owner_npk = NullifierPublicKey::from(&owner_nsk); + let owner_vpk = ViewingPublicKey::from_seed(&[93u8; 32], &[94u8; 32]); + let owner_id = AccountId::for_regular_private_account(&owner_npk, 0); + + // The ATA holding must stay public (per the confirmed PDA finding), so it's seeded + // directly rather than via a real `Create` transaction. + let seed = compute_ata_seed(Ids::token_program(), owner_id, Ids::token_definition()); + let ata_id = get_associated_token_account_id(&Ids::ata_program(), &seed); + let ata_account = Account { + program_owner: Ids::token_program(), + balance: 0_u128, + data: Data::from(&TokenHolding::Fungible { + definition_id: Ids::token_definition(), + balance: 1_000_000_u128, + }), + nonce: Nonce(0), + }; + state.force_insert_account(ata_id, ata_account.clone()); + + let owner_pre = AccountWithMetadata::new(Account::default(), true, owner_id); + let ata_pre = AccountWithMetadata::new(ata_account, false, ata_id); + let def_pre = AccountWithMetadata::new( + state.get_account_by_id(Ids::token_definition()), + false, + Ids::token_definition(), + ); + + let burn_amount = 300_000_u128; + let instruction = ata_core::Instruction::Burn { + token_program_id: Ids::token_program(), + amount: burn_amount, + }; + + let shared_secret = SharedSecretKey::encapsulate_deterministic(&owner_vpk, &[0u8; 32], 0).0; + + let ata_program = Program::new(ata_methods::ATA_ELF.to_vec().into()).unwrap(); + let token_program = Program::new(token_methods::TOKEN_ELF.to_vec().into()).unwrap(); + let program_with_deps = ProgramWithDependencies::new( + ata_program, + HashMap::from([(Ids::token_program(), token_program)]), + ); + + let (output, proof) = execute_and_prove( + vec![owner_pre, ata_pre, def_pre], + Program::serialize_instruction(instruction).unwrap(), + vec![ + InputAccountIdentity::PrivateAuthorizedInit { + epk: EphemeralPublicKey(Vec::new()), + view_tag: EncryptedAccountData::compute_view_tag(&owner_npk, &owner_vpk), + ssk: shared_secret, + nsk: owner_nsk, + identifier: 0, + }, + InputAccountIdentity::Public, + InputAccountIdentity::Public, + ], + &program_with_deps, + ) + .unwrap(); + + let message = + Message::try_from_circuit_output(vec![ata_id, Ids::token_definition()], vec![], output) + .unwrap(); + let witness_set = WitnessSet::for_message(&message, proof, &[]); + state + .transition_from_privacy_preserving_transaction( + &PrivacyPreservingTransaction::new(message, witness_set), + 0, + 0, + ) + .unwrap(); + + assert_eq!( + state.get_account_by_id(ata_id), + Account { + program_owner: Ids::token_program(), + balance: 0_u128, + data: Data::from(&TokenHolding::Fungible { + definition_id: Ids::token_definition(), + balance: 1_000_000_u128 - burn_amount, + }), + nonce: Nonce(0), + } + ); + assert_eq!( + state.get_account_by_id(Ids::token_definition()), + Account { + program_owner: Ids::token_program(), + balance: 0_u128, + data: Data::from(&TokenDefinition::Fungible { + name: String::from("Gold"), + total_supply: 1_000_000_u128 - burn_amount, + metadata_id: None, + authority: None, + }), + nonce: Nonce(0), + } + ); + + let owner_expected = Account { + nonce: Nonce::private_account_nonce_init(&owner_id), + ..Account::default() + }; + assert!(state + .get_proof_for_commitment(&Commitment::new(&owner_id, &owner_expected)) + .is_some()); +} + +// Marvin-todo +/// Composes the `GROUP` dimension with the signer-authorization finding just proven above: a +/// group-owned owner (GMS distributed through the real seal/unseal handshake, exactly as in +/// `token_group_owned_holding_shared_control`) signs an `ATA::Burn` via `PrivateAuthorizedInit`. +/// "Bob" — who only ever receives the sealed GMS, never Alice's `GroupKeyHolder` object — +/// independently re-derives the identical nsk/npk and successfully signs for the shared ATA +/// owner identity. +#[test] +fn ata_group_owned_owner_signing() { + let mut state = V03State::new(); + deploy_programs(&mut state); + state.force_insert_account(Ids::token_definition(), Accounts::token_definition_init()); + + // Alice creates the group and derives the shared owner identity's keys. + let alice_holder = GroupKeyHolder::new(); + let derivation_seed = [13_u8; 32]; + let alice_keys = alice_holder.derive_keys_for_shared_account(&derivation_seed); + let owner_npk = alice_keys.generate_nullifier_public_key(); + let owner_id = AccountId::for_regular_private_account(&owner_npk, 0); + + // Alice distributes the GMS to Bob via the real seal/unseal handshake. + let bob_sealing_keys = SecretSpendingKey([17_u8; 32]).produce_private_key_holder(None); + let bob_sealing_vpk = bob_sealing_keys.generate_viewing_public_key(); + let bob_sealing_vsk = bob_sealing_keys.viewing_secret_key; + let sealed_gms = alice_holder.seal_for(&SealingPublicKey::from_bytes( + bob_sealing_vpk.to_bytes().to_vec(), + )); + let bob_holder = + GroupKeyHolder::unseal(&sealed_gms, &bob_sealing_vsk).expect("Bob must unseal the GMS"); + + // Bob independently re-derives the same shared owner keys and is the one who signs below. + let bob_keys = bob_holder.derive_keys_for_shared_account(&derivation_seed); + let bob_nsk = bob_keys.nullifier_secret_key; + let bob_vpk = bob_keys.generate_viewing_public_key(); + assert_eq!( + bob_keys.generate_nullifier_public_key(), + owner_npk, + "Bob must derive the identical npk as Alice from the shared GMS" + ); + + // The ATA holding must stay public (per the confirmed PDA finding), so it's seeded + // directly rather than via a real `Create` transaction. + let seed = compute_ata_seed(Ids::token_program(), owner_id, Ids::token_definition()); + let ata_id = get_associated_token_account_id(&Ids::ata_program(), &seed); + let ata_account = Account { + program_owner: Ids::token_program(), + balance: 0_u128, + data: Data::from(&TokenHolding::Fungible { + definition_id: Ids::token_definition(), + balance: 1_000_000_u128, + }), + nonce: Nonce(0), + }; + state.force_insert_account(ata_id, ata_account.clone()); + + let owner_pre = AccountWithMetadata::new(Account::default(), true, owner_id); + let ata_pre = AccountWithMetadata::new(ata_account, false, ata_id); + let def_pre = AccountWithMetadata::new( + state.get_account_by_id(Ids::token_definition()), + false, + Ids::token_definition(), + ); + + let burn_amount = 300_000_u128; + let instruction = ata_core::Instruction::Burn { + token_program_id: Ids::token_program(), + amount: burn_amount, + }; + + let shared_secret = SharedSecretKey::encapsulate_deterministic(&bob_vpk, &[0u8; 32], 0).0; + + let ata_program = Program::new(ata_methods::ATA_ELF.to_vec().into()).unwrap(); + let token_program = Program::new(token_methods::TOKEN_ELF.to_vec().into()).unwrap(); + let program_with_deps = ProgramWithDependencies::new( + ata_program, + HashMap::from([(Ids::token_program(), token_program)]), + ); + + let (output, proof) = execute_and_prove( + vec![owner_pre, ata_pre, def_pre], + Program::serialize_instruction(instruction).unwrap(), + vec![ + InputAccountIdentity::PrivateAuthorizedInit { + epk: EphemeralPublicKey(Vec::new()), + view_tag: EncryptedAccountData::compute_view_tag(&owner_npk, &bob_vpk), + ssk: shared_secret, + nsk: bob_nsk, + identifier: 0, + }, + InputAccountIdentity::Public, + InputAccountIdentity::Public, + ], + &program_with_deps, + ) + .unwrap(); + + let message = + Message::try_from_circuit_output(vec![ata_id, Ids::token_definition()], vec![], output) + .unwrap(); + let witness_set = WitnessSet::for_message(&message, proof, &[]); + state + .transition_from_privacy_preserving_transaction( + &PrivacyPreservingTransaction::new(message, witness_set), + 0, + 0, + ) + .unwrap(); + + assert_eq!( + state.get_account_by_id(ata_id), + Account { + program_owner: Ids::token_program(), + balance: 0_u128, + data: Data::from(&TokenHolding::Fungible { + definition_id: Ids::token_definition(), + balance: 1_000_000_u128 - burn_amount, + }), + nonce: Nonce(0), + } + ); + + let owner_expected = Account { + nonce: Nonce::private_account_nonce_init(&owner_id), + ..Account::default() + }; + assert!(state + .get_proof_for_commitment(&Commitment::new(&owner_id, &owner_expected)) + .is_some()); +} diff --git a/programs/integration_tests/tests/token.rs b/programs/integration_tests/tests/token.rs index bb276d2..fe0dc5f 100644 --- a/programs/integration_tests/tests/token.rs +++ b/programs/integration_tests/tests/token.rs @@ -1,3 +1,7 @@ +use key_protocol::key_management::{ + group_key_holder::{GroupKeyHolder, SealingPublicKey}, + secret_holders::SecretSpendingKey, +}; use nssa::{ execute_and_prove, privacy_preserving_transaction::{Message, PrivacyPreservingTransaction, WitnessSet}, @@ -8,7 +12,8 @@ use nssa::{ use nssa_core::{ account::{Account, AccountId, AccountWithMetadata, Data, Nonce}, encryption::{EphemeralPublicKey, ViewingPublicKey}, - Commitment, EncryptedAccountData, InputAccountIdentity, NullifierPublicKey, NullifierSecretKey, + Commitment, EncryptedAccountData, InputAccountIdentity, Nullifier, NullifierPublicKey, + NullifierSecretKey, }; use token_core::{TokenDefinition, TokenHolding}; @@ -758,6 +763,83 @@ fn token_shielded_transfer() { .is_some()); } +/// Shielded transaction to a private account using the account's `nsk`. +/// `token_shielded_transfer` only uses the account's `npk`; thus, `PrivateUnauthorized` private. +#[test] +fn token_shielded_transfer_authorized_private_init() { + let mut state = state_for_token_tests(); + let amount = 500_000_u128; + + let sender_id = Ids::holder(); + let sender_account = state.get_account_by_id(sender_id); + let sender_nonce = sender_account.nonce; + + let recipient_nsk = PrivateKeys::recipient_nsk(); + let recipient_npk = PrivateKeys::recipient_npk(); + let recipient_vpk = PrivateKeys::recipient_vpk(); + let recipient_id = PrivateKeys::recipient_id(); + + let sender_pre = AccountWithMetadata::new(sender_account, true, sender_id); + let recipient_pre = AccountWithMetadata::new(Account::default(), true, recipient_id); + + let shared_secret = SharedSecretKey::encapsulate_deterministic(&recipient_vpk, &[0u8; 32], 0).0; + + let instruction = token_core::Instruction::Transfer { + amount_to_transfer: amount, + }; + let (output, proof) = execute_and_prove( + vec![sender_pre, recipient_pre], + Program::serialize_instruction(instruction).unwrap(), + vec![ + InputAccountIdentity::Public, + InputAccountIdentity::PrivateAuthorizedInit { + epk: EphemeralPublicKey(Vec::new()), + view_tag: EncryptedAccountData::compute_view_tag(&recipient_npk, &recipient_vpk), + ssk: shared_secret, + nsk: recipient_nsk, + identifier: 0, + }, + ], + &token_program().into(), + ) + .unwrap(); + + let message = + Message::try_from_circuit_output(vec![sender_id], vec![sender_nonce], output).unwrap(); + + let witness_set = WitnessSet::for_message(&message, proof, &[&Keys::holder_key()]); + let tx = PrivacyPreservingTransaction::new(message, witness_set); + state + .transition_from_privacy_preserving_transaction(&tx, 0, 0) + .unwrap(); + + assert_eq!( + state.get_account_by_id(sender_id), + Account { + program_owner: Ids::token_program(), + balance: 0, + data: Data::from(&TokenHolding::Fungible { + definition_id: Ids::token_definition(), + balance: 1_000_000 - amount, + }), + nonce: Nonce(1), + } + ); + + let recipient_account = Account { + program_owner: Ids::token_program(), + balance: 0, + data: Data::from(&TokenHolding::Fungible { + definition_id: Ids::token_definition(), + balance: amount, + }), + nonce: Nonce::private_account_nonce_init(&recipient_id), + }; + assert!(state + .get_proof_for_commitment(&Commitment::new(&recipient_id, &recipient_account)) + .is_some()); +} + #[test] fn token_private_transfer() { let mut state = state_for_token_tests(); @@ -942,6 +1024,910 @@ fn token_deshielded_transfer() { .is_some()); } +/// Mints directly to a new recipient private holding (`PrivateUnauthorized`). +/// The recipient's cooperation is unnecessary; only known of the recipient's `npk`, `vpk`. +#[test] +fn token_mint_shielded_to_private_unauthorized() { + let mut state = state_for_token_tests_without_recipient(); + let amount_to_mint = 500_000_u128; + + let recipient_npk = PrivateKeys::recipient_npk(); + let recipient_vpk = PrivateKeys::recipient_vpk(); + let recipient_id = PrivateKeys::recipient_id(); + + let definition_account = state.get_account_by_id(Ids::token_definition()); + let definition_nonce = definition_account.nonce; + let definition_pre = + AccountWithMetadata::new(definition_account, true, Ids::token_definition()); + let recipient_pre = AccountWithMetadata::new(Account::default(), false, recipient_id); + + let shared_secret = SharedSecretKey::encapsulate_deterministic(&recipient_vpk, &[0u8; 32], 0).0; + + let instruction = token_core::Instruction::Mint { amount_to_mint }; + let (output, proof) = execute_and_prove( + vec![definition_pre, recipient_pre], + Program::serialize_instruction(instruction).unwrap(), + vec![ + InputAccountIdentity::Public, + InputAccountIdentity::PrivateUnauthorized { + epk: EphemeralPublicKey(Vec::new()), + view_tag: EncryptedAccountData::compute_view_tag(&recipient_npk, &recipient_vpk), + npk: recipient_npk, + ssk: shared_secret, + identifier: 0, + }, + ], + &token_program().into(), + ) + .unwrap(); + + let message = Message::try_from_circuit_output( + vec![Ids::token_definition()], + vec![definition_nonce], + output, + ) + .unwrap(); + + let witness_set = WitnessSet::for_message(&message, proof, &[&Keys::def_key()]); + let tx = PrivacyPreservingTransaction::new(message, witness_set); + state + .transition_from_privacy_preserving_transaction(&tx, 0, 0) + .unwrap(); + + assert_eq!( + state.get_account_by_id(Ids::token_definition()), + Account { + program_owner: Ids::token_program(), + balance: 0_u128, + data: Data::from(&TokenDefinition::Fungible { + name: String::from("Gold"), + total_supply: 1_000_000_u128 + amount_to_mint, + metadata_id: None, + authority: Some(Ids::token_definition()), + }), + nonce: Nonce(1), + } + ); + + let recipient_account = Account { + program_owner: Ids::token_program(), + balance: 0, + data: Data::from(&TokenHolding::Fungible { + definition_id: Ids::token_definition(), + balance: amount_to_mint, + }), + nonce: Nonce::private_account_nonce_init(&recipient_id), + }; + assert!(state + .get_proof_for_commitment(&Commitment::new(&recipient_id, &recipient_account)) + .is_some()); +} + +/// Mints directly to a new recipient private holding (`PrivateAuthorizedInit`). +/// This requires the recipient's secret key `nsk`. +#[test] +fn token_mint_authorized_private_init() { + let mut state = state_for_token_tests_without_recipient(); + let amount_to_mint = 500_000_u128; + + let recipient_nsk = PrivateKeys::recipient_nsk(); + let recipient_npk = PrivateKeys::recipient_npk(); + let recipient_vpk = PrivateKeys::recipient_vpk(); + let recipient_id = PrivateKeys::recipient_id(); + + let definition_account = state.get_account_by_id(Ids::token_definition()); + let definition_nonce = definition_account.nonce; + let definition_pre = + AccountWithMetadata::new(definition_account, true, Ids::token_definition()); + let recipient_pre = AccountWithMetadata::new(Account::default(), true, recipient_id); + + let shared_secret = SharedSecretKey::encapsulate_deterministic(&recipient_vpk, &[0u8; 32], 0).0; + + let instruction = token_core::Instruction::Mint { amount_to_mint }; + let (output, proof) = execute_and_prove( + vec![definition_pre, recipient_pre], + Program::serialize_instruction(instruction).unwrap(), + vec![ + InputAccountIdentity::Public, + InputAccountIdentity::PrivateAuthorizedInit { + epk: EphemeralPublicKey(Vec::new()), + view_tag: EncryptedAccountData::compute_view_tag(&recipient_npk, &recipient_vpk), + ssk: shared_secret, + nsk: recipient_nsk, + identifier: 0, + }, + ], + &token_program().into(), + ) + .unwrap(); + + let message = Message::try_from_circuit_output( + vec![Ids::token_definition()], + vec![definition_nonce], + output, + ) + .unwrap(); + + let witness_set = WitnessSet::for_message(&message, proof, &[&Keys::def_key()]); + let tx = PrivacyPreservingTransaction::new(message, witness_set); + state + .transition_from_privacy_preserving_transaction(&tx, 0, 0) + .unwrap(); + + assert_eq!( + state.get_account_by_id(Ids::token_definition()), + Account { + program_owner: Ids::token_program(), + balance: 0_u128, + data: Data::from(&TokenDefinition::Fungible { + name: String::from("Gold"), + total_supply: 1_000_000_u128 + amount_to_mint, + metadata_id: None, + authority: Some(Ids::token_definition()), + }), + nonce: Nonce(1), + } + ); + + let recipient_account = Account { + program_owner: Ids::token_program(), + balance: 0, + data: Data::from(&TokenHolding::Fungible { + definition_id: Ids::token_definition(), + balance: amount_to_mint, + }), + nonce: Nonce::private_account_nonce_init(&recipient_id), + }; + assert!(state + .get_proof_for_commitment(&Commitment::new(&recipient_id, &recipient_account)) + .is_some()); +} + +/// Mints directly to a pre-existing recipient private holding +/// This requires the recipient's secret key `nsk`. +#[test] +fn token_mint_into_existing_private_holding() { + let mut state = state_for_token_tests_without_recipient(); + let pre_balance = 500_000_u128; + let amount_to_mint = 250_000_u128; + + let recipient_nsk = PrivateKeys::recipient_nsk(); + let recipient_npk = PrivateKeys::recipient_npk(); + let recipient_vpk = PrivateKeys::recipient_vpk(); + let recipient_id = PrivateKeys::recipient_id(); + + let recipient_pre = Account { + program_owner: Ids::token_program(), + balance: 0, + data: Data::from(&TokenHolding::Fungible { + definition_id: Ids::token_definition(), + balance: pre_balance, + }), + nonce: Nonce::private_account_nonce_init(&recipient_id), + }; + state = state.with_private_accounts([( + Commitment::new(&recipient_id, &recipient_pre), + Nullifier::for_account_initialization(&recipient_id), + )]); + assert!( + state + .get_proof_for_commitment(&Commitment::new(&recipient_id, &recipient_pre)) + .is_some(), + "seeded balance must land before the existing-holding mint under test" + ); + + let membership_proof = state + .get_proof_for_commitment(&Commitment::new(&recipient_id, &recipient_pre)) + .expect("recipient's commitment must be in the set"); + + let definition_account = state.get_account_by_id(Ids::token_definition()); + let definition_nonce = definition_account.nonce; + let definition_pre = + AccountWithMetadata::new(definition_account, true, Ids::token_definition()); + let existing_recipient_pre = + AccountWithMetadata::new(recipient_pre.clone(), true, recipient_id); + + let shared_secret = + SharedSecretKey::encapsulate_deterministic(&recipient_vpk, &[0u8; 32], 0).0; + + let (output, second_proof) = execute_and_prove( + vec![definition_pre, existing_recipient_pre], + Program::serialize_instruction(token_core::Instruction::Mint { + amount_to_mint, + }) + .unwrap(), + vec![ + InputAccountIdentity::Public, + InputAccountIdentity::PrivateAuthorizedUpdate { + epk: EphemeralPublicKey(Vec::new()), + view_tag: EncryptedAccountData::compute_view_tag(&recipient_npk, &recipient_vpk), + ssk: shared_secret, + nsk: recipient_nsk, + membership_proof, + identifier: 0, + }, + ], + &token_program().into(), + ) + .unwrap(); + + let message = Message::try_from_circuit_output( + vec![Ids::token_definition()], + vec![definition_nonce], + output, + ) + .unwrap(); + let witness = + WitnessSet::for_message(&message, second_proof, &[&Keys::def_key()]); + state + .transition_from_privacy_preserving_transaction( + &PrivacyPreservingTransaction::new(message, witness), + 0, + 0, + ) + .unwrap(); + + assert_eq!( + state.get_account_by_id(Ids::token_definition()), + Account { + program_owner: Ids::token_program(), + balance: 0_u128, + data: Data::from(&TokenDefinition::Fungible { + name: String::from("Gold"), + total_supply: 1_000_000_u128 + amount_to_mint, + metadata_id: None, + authority: Some(Ids::token_definition()), + }), + nonce: Nonce(1), + } + ); + + let recipient_nonce_after = Nonce::private_account_nonce_init(&recipient_id) + .private_account_nonce_increment(&recipient_nsk); + let recipient_after_second_mint = Account { + program_owner: Ids::token_program(), + balance: 0, + data: Data::from(&TokenHolding::Fungible { + definition_id: Ids::token_definition(), + balance: pre_balance + amount_to_mint, + }), + nonce: recipient_nonce_after, + }; + assert!(state + .get_proof_for_commitment(&Commitment::new( + &recipient_id, + &recipient_after_second_mint + )) + .is_some()); +} + +/// Burns from an existing private holding (`PrivateAuthorizedUpdate`). +#[test] +fn token_private_burn() { + let mut state = state_for_token_tests(); + let holding_balance = 500_000_u128; + let burn_amount = 200_000_u128; + + let holder_npk = PrivateKeys::recipient_npk(); + let holder_nsk = PrivateKeys::recipient_nsk(); + let holder_vpk = PrivateKeys::recipient_vpk(); + let holder_id = PrivateKeys::recipient_id(); + + // Predefined holding account to burn from. + let holder_account = Account { + program_owner: Ids::token_program(), + balance: 0, + data: Data::from(&TokenHolding::Fungible { + definition_id: Ids::token_definition(), + balance: holding_balance, + }), + nonce: Nonce::private_account_nonce_init(&holder_id), + }; + let holder_commitment = Commitment::new(&holder_id, &holder_account); + state = state.with_private_accounts([( + holder_commitment.clone(), + Nullifier::for_account_initialization(&holder_id), + )]); + let membership_proof = state + .get_proof_for_commitment(&holder_commitment) + .expect("holder's commitment must be in the set"); + + let shared_secret = SharedSecretKey::encapsulate_deterministic(&holder_vpk, &[0u8; 32], 0).0; + + let definition_pre = AccountWithMetadata::new( + state.get_account_by_id(Ids::token_definition()), + false, + Ids::token_definition(), + ); + let holder_pre = AccountWithMetadata::new(holder_account.clone(), true, holder_id); + + let instruction = token_core::Instruction::Burn { + amount_to_burn: burn_amount, + }; + let (output, proof) = execute_and_prove( + vec![definition_pre, holder_pre], + Program::serialize_instruction(instruction).unwrap(), + vec![ + InputAccountIdentity::Public, + InputAccountIdentity::PrivateAuthorizedUpdate { + epk: EphemeralPublicKey(Vec::new()), + view_tag: EncryptedAccountData::compute_view_tag(&holder_npk, &holder_vpk), + ssk: shared_secret, + nsk: holder_nsk, + membership_proof, + identifier: 0, + }, + ], + &token_program().into(), + ) + .unwrap(); + + let message = + Message::try_from_circuit_output(vec![Ids::token_definition()], vec![], output).unwrap(); + + let witness_set = WitnessSet::for_message(&message, proof, &[]); + let tx = PrivacyPreservingTransaction::new(message, witness_set); + state + .transition_from_privacy_preserving_transaction(&tx, 0, 0) + .unwrap(); + + assert_eq!( + state.get_account_by_id(Ids::token_definition()), + Account { + program_owner: Ids::token_program(), + balance: 0_u128, + data: Data::from(&TokenDefinition::Fungible { + name: String::from("Gold"), + total_supply: 1_000_000_u128 - burn_amount, + metadata_id: None, + authority: Some(Ids::token_definition()), + }), + nonce: Nonce(0), + } + ); + + let new_holder_account = Account { + program_owner: Ids::token_program(), + balance: 0, + data: Data::from(&TokenHolding::Fungible { + definition_id: Ids::token_definition(), + balance: holding_balance - burn_amount, + }), + nonce: Nonce::private_account_nonce_init(&holder_id) + .private_account_nonce_increment(&holder_nsk), + }; + assert!(state + .get_proof_for_commitment(&Commitment::new(&holder_id, &new_holder_account)) + .is_some()); +} + +/// Token transfer into a pre-existing Token holding account. This requires +/// the account's `nsk`; `PrivateAuthorizedUpdate`. +#[test] +fn token_transfer_into_existing_private_holding() { + let mut state = state_for_token_tests(); + let init_balance = 500_000_u128; + let second_amount = 100_000_u128; + + let recipient_npk = PrivateKeys::recipient_npk(); + let recipient_nsk = PrivateKeys::recipient_nsk(); + let recipient_vpk = PrivateKeys::recipient_vpk(); + let recipient_id = PrivateKeys::recipient_id(); + + let recipient_account = Account { + program_owner: Ids::token_program(), + balance: 0, + data: Data::from(&TokenHolding::Fungible { + definition_id: Ids::token_definition(), + balance: init_balance, + }), + nonce: Nonce::private_account_nonce_init(&recipient_id), + }; + let recipient_commitment = Commitment::new(&recipient_id, &recipient_account); + state = state.with_private_accounts([( + recipient_commitment.clone(), + Nullifier::for_account_initialization(&recipient_id), + )]); + let membership_proof = state + .get_proof_for_commitment(&recipient_commitment) + .expect("recipient's commitment must be in the set after seeding"); + + let sender_id = Ids::holder(); + let sender_account = state.get_account_by_id(sender_id); + let sender_nonce = sender_account.nonce; + + let shared_secret = SharedSecretKey::encapsulate_deterministic(&recipient_vpk, &[0u8; 32], 0).0; + + let sender_pre = AccountWithMetadata::new(sender_account, true, sender_id); + let recipient_pre = AccountWithMetadata::new(recipient_account.clone(), true, recipient_id); + + let instruction = token_core::Instruction::Transfer { + amount_to_transfer: second_amount, + }; + let (output, proof) = execute_and_prove( + vec![sender_pre, recipient_pre], + Program::serialize_instruction(instruction).unwrap(), + vec![ + InputAccountIdentity::Public, + InputAccountIdentity::PrivateAuthorizedUpdate { + epk: EphemeralPublicKey(Vec::new()), + view_tag: EncryptedAccountData::compute_view_tag(&recipient_npk, &recipient_vpk), + ssk: shared_secret, + nsk: recipient_nsk, + membership_proof, + identifier: 0, + }, + ], + &token_program().into(), + ) + .unwrap(); + + let message = + Message::try_from_circuit_output(vec![sender_id], vec![sender_nonce], output).unwrap(); + + let witness_set = WitnessSet::for_message(&message, proof, &[&Keys::holder_key()]); + let tx = PrivacyPreservingTransaction::new(message, witness_set); + state + .transition_from_privacy_preserving_transaction(&tx, 0, 0) + .unwrap(); + + assert_eq!( + state.get_account_by_id(sender_id), + Account { + program_owner: Ids::token_program(), + balance: 0, + data: Data::from(&TokenHolding::Fungible { + definition_id: Ids::token_definition(), + // `first_amount` was seeded directly into the recipient, never debited from + // the sender — only the real transfer (`second_amount`) actually happened. + balance: 1_000_000 - second_amount, + }), + nonce: Nonce(1), + } + ); + + let recipient_nonce_after = Nonce::private_account_nonce_init(&recipient_id) + .private_account_nonce_increment(&recipient_nsk); + let new_recipient_account = Account { + program_owner: Ids::token_program(), + balance: 0, + data: Data::from(&TokenHolding::Fungible { + definition_id: Ids::token_definition(), + balance: init_balance + second_amount, + }), + nonce: recipient_nonce_after, + }; + assert!(state + .get_proof_for_commitment(&Commitment::new(&recipient_id, &new_recipient_account)) + .is_some()); +} + +// Marvin-todo +/// Fully private counterpart to `token_transfer_into_existing_private_holding`: instead of a +/// *public* sender crediting an existing private recipient, both legs are private and the +/// recipient already exists (not fresh, unlike `token_private_transfer`'s new recipient). This +/// is a new combination — two distinct private accounts, both driven by +/// `PrivateAuthorizedUpdate` (spend + credit-existing) in the same transaction — that neither +/// existing test covers. `Token::Transfer` has no definition-account parameter at all, so with +/// both legs private there is no public account anywhere in this transaction: no signer, no +/// public message ids. +#[test] +fn token_private_transfer_into_existing_private_holding() { + let mut state = state_for_token_tests(); + let sender_initial_balance = 500_000_u128; + let recipient_initial_balance = 300_000_u128; + let transfer_amount = 200_000_u128; + + let sender_npk = PrivateKeys::recipient_npk(); + let sender_nsk = PrivateKeys::recipient_nsk(); + let sender_vpk = PrivateKeys::recipient_vpk(); + let sender_id = PrivateKeys::recipient_id(); + + let recipient_npk = PrivateKeys::holder_npk(); + let recipient_nsk = PrivateKeys::holder_nsk(); + let recipient_vpk = PrivateKeys::holder_vpk(); + let recipient_id = PrivateKeys::holder_id(); + + // Seed both sides directly — neither needs a real prior transaction to exist. + let sender_account = Account { + program_owner: Ids::token_program(), + balance: 0, + data: Data::from(&TokenHolding::Fungible { + definition_id: Ids::token_definition(), + balance: sender_initial_balance, + }), + nonce: Nonce::private_account_nonce_init(&sender_id), + }; + let recipient_account = Account { + program_owner: Ids::token_program(), + balance: 0, + data: Data::from(&TokenHolding::Fungible { + definition_id: Ids::token_definition(), + balance: recipient_initial_balance, + }), + nonce: Nonce::private_account_nonce_init(&recipient_id), + }; + state = state.with_private_accounts([ + ( + Commitment::new(&sender_id, &sender_account), + Nullifier::for_account_initialization(&sender_id), + ), + ( + Commitment::new(&recipient_id, &recipient_account), + Nullifier::for_account_initialization(&recipient_id), + ), + ]); + + let sender_membership_proof = state + .get_proof_for_commitment(&Commitment::new(&sender_id, &sender_account)) + .expect("sender's commitment must be in the set"); + let recipient_membership_proof = state + .get_proof_for_commitment(&Commitment::new(&recipient_id, &recipient_account)) + .expect("recipient's commitment must be in the set"); + + let sender_shared_secret = + SharedSecretKey::encapsulate_deterministic(&sender_vpk, &[0u8; 32], 0).0; + let recipient_shared_secret = + SharedSecretKey::encapsulate_deterministic(&recipient_vpk, &[0u8; 32], 1).0; + + let sender_pre = AccountWithMetadata::new(sender_account.clone(), true, sender_id); + let recipient_pre = AccountWithMetadata::new(recipient_account.clone(), true, recipient_id); + + let instruction = token_core::Instruction::Transfer { + amount_to_transfer: transfer_amount, + }; + let (output, proof) = execute_and_prove( + vec![sender_pre, recipient_pre], + Program::serialize_instruction(instruction).unwrap(), + vec![ + InputAccountIdentity::PrivateAuthorizedUpdate { + epk: EphemeralPublicKey(Vec::new()), + view_tag: EncryptedAccountData::compute_view_tag(&sender_npk, &sender_vpk), + ssk: sender_shared_secret, + nsk: sender_nsk, + membership_proof: sender_membership_proof, + identifier: 0, + }, + InputAccountIdentity::PrivateAuthorizedUpdate { + epk: EphemeralPublicKey(Vec::new()), + view_tag: EncryptedAccountData::compute_view_tag(&recipient_npk, &recipient_vpk), + ssk: recipient_shared_secret, + nsk: recipient_nsk, + membership_proof: recipient_membership_proof, + identifier: 0, + }, + ], + &token_program().into(), + ) + .unwrap(); + + let message = Message::try_from_circuit_output(vec![], vec![], output).unwrap(); + let witness_set = WitnessSet::for_message(&message, proof, &[]); + state + .transition_from_privacy_preserving_transaction( + &PrivacyPreservingTransaction::new(message, witness_set), + 0, + 0, + ) + .unwrap(); + + let sender_nonce_after = + Nonce::private_account_nonce_init(&sender_id).private_account_nonce_increment(&sender_nsk); + let new_sender_account = Account { + program_owner: Ids::token_program(), + balance: 0, + data: Data::from(&TokenHolding::Fungible { + definition_id: Ids::token_definition(), + balance: sender_initial_balance - transfer_amount, + }), + nonce: sender_nonce_after, + }; + assert!(state + .get_proof_for_commitment(&Commitment::new(&sender_id, &new_sender_account)) + .is_some()); + + let recipient_nonce_after = Nonce::private_account_nonce_init(&recipient_id) + .private_account_nonce_increment(&recipient_nsk); + let new_recipient_account = Account { + program_owner: Ids::token_program(), + balance: 0, + data: Data::from(&TokenHolding::Fungible { + definition_id: Ids::token_definition(), + balance: recipient_initial_balance + transfer_amount, + }), + nonce: recipient_nonce_after, + }; + assert!(state + .get_proof_for_commitment(&Commitment::new(&recipient_id, &new_recipient_account)) + .is_some()); +} + +/// Initializes a private holding account directly (private account secret keys are known). +/// `InitializeAccount` requires `account_to_initialize` to be authorized. E.g., for private +/// accounts must be `PrivateAuthorizedInit` and not `PrivateUnauthorized`; the account owner +/// must supply their own `nsk`. +#[test] +fn token_initialize_private_account_succeeds_for_canonical_definition() { + let mut state = state_for_token_tests_without_recipient(); + + let owner_nsk = PrivateKeys::recipient_nsk(); + let owner_npk = PrivateKeys::recipient_npk(); + let owner_vpk = PrivateKeys::recipient_vpk(); + let owner_id = PrivateKeys::recipient_id(); + + let definition_pre = AccountWithMetadata::new( + state.get_account_by_id(Ids::token_definition()), + false, + Ids::token_definition(), + ); + let account_to_init_pre = AccountWithMetadata::new(Account::default(), true, owner_id); + + let shared_secret = SharedSecretKey::encapsulate_deterministic(&owner_vpk, &[0u8; 32], 0).0; + + let instruction = token_core::Instruction::InitializeAccount; + let (output, proof) = execute_and_prove( + vec![definition_pre, account_to_init_pre], + Program::serialize_instruction(instruction).unwrap(), + vec![ + InputAccountIdentity::Public, + InputAccountIdentity::PrivateAuthorizedInit { + epk: EphemeralPublicKey(Vec::new()), + view_tag: EncryptedAccountData::compute_view_tag(&owner_npk, &owner_vpk), + ssk: shared_secret, + nsk: owner_nsk, + identifier: 0, + }, + ], + &token_program().into(), + ) + .unwrap(); + + let message = + Message::try_from_circuit_output(vec![Ids::token_definition()], vec![], output).unwrap(); + + let witness_set = WitnessSet::for_message(&message, proof, &[]); + let tx = PrivacyPreservingTransaction::new(message, witness_set); + state + .transition_from_privacy_preserving_transaction(&tx, 0, 0) + .unwrap(); + + let expected_account = Account { + program_owner: Ids::token_program(), + balance: 0, + data: Data::from(&TokenHolding::Fungible { + definition_id: Ids::token_definition(), + balance: 0, + }), + nonce: Nonce::private_account_nonce_init(&owner_id), + }; + assert!(state + .get_proof_for_commitment(&Commitment::new(&owner_id, &expected_account)) + .is_some()); +} + +// TODO: think this is unnecessary; double check. +/// Confirms `InitializeAccount` is self-service-only: unlike `Transfer`/`Mint`, whose recipient +/// host logic never asserts `is_authorized`, the guest's `#[account(init, signer)]` on +/// `account_to_initialize` requires `is_authorized == true` — enforced by the SPEL macro's own +/// account validation before `token_program::initialize::initialize_account`'s host logic +/// (which carries the same assert as defense in depth) ever runs. The only private identity +/// variant satisfying that for a fresh account is `PrivateAuthorizedInit`, which requires +/// supplying `nsk` directly — so a third party cannot initialize a private holding on behalf of +/// an `(npk, vpk, identifier)` whose `nsk` they don't possess. Attempting it via +/// `PrivateUnauthorized` (the variant that *would* allow third-party setup elsewhere) is +/// rejected at the framework's signer check, since that variant forces `is_authorized: false`. +#[test] +fn token_initialize_private_account_without_nsk_is_not_expressible() { + let state = state_for_token_tests_without_recipient(); + + let recipient_npk = PrivateKeys::recipient_npk(); + let recipient_vpk = PrivateKeys::recipient_vpk(); + let recipient_id = PrivateKeys::recipient_id(); + + let definition_pre = AccountWithMetadata::new( + state.get_account_by_id(Ids::token_definition()), + false, + Ids::token_definition(), + ); + let account_to_init_pre = AccountWithMetadata::new(Account::default(), false, recipient_id); + + let shared_secret = SharedSecretKey::encapsulate_deterministic(&recipient_vpk, &[0u8; 32], 0).0; + + let result = execute_and_prove( + vec![definition_pre, account_to_init_pre], + Program::serialize_instruction(token_core::Instruction::InitializeAccount).unwrap(), + vec![ + InputAccountIdentity::Public, + InputAccountIdentity::PrivateUnauthorized { + epk: EphemeralPublicKey(Vec::new()), + view_tag: EncryptedAccountData::compute_view_tag(&recipient_npk, &recipient_vpk), + npk: recipient_npk, + ssk: shared_secret, + identifier: 0, + }, + ], + &token_program().into(), + ); + + let err = result.expect_err( + "initializing a private holding without its nsk must be rejected: InitializeAccount \ + requires is_authorized == true, but PrivateUnauthorized forces is_authorized == false", + ); + let message = format!("{err:?}"); + assert!( + message.contains("must be a signer"), + "expected the self-service-only rejection, got a different error: {message}" + ); +} + +/// Two independent parties share control of one private Token holding via a `GroupKeyHolder` +/// Group Master Secret (GMS), distributed through the real seal/unseal handshake — not by +/// reusing key material directly — so the test proves actual sharing, not code reuse. "Alice" +/// creates the group and shields tokens into the shared holding; "Bob" only ever receives the +/// *sealed* GMS, independently re-derives the identical nsk/npk from it, and successfully +/// burns from the same holding neither of them personally owns. Validates the `GROUP` Q2 +/// dimension: sharing a private account (group-owned) used as a program account. +/// TODO: add a function for spending +#[test] +fn token_group_owned_holding_shared_control_burn() { + let mut state = state_for_token_tests(); + let shield_amount = 500_000_u128; + let burn_amount = 200_000_u128; + + // Alice creates the group and derives the shared account's keys. + let alice_holder = GroupKeyHolder::new(); + let derivation_seed = [7_u8; 32]; + let alice_keys = alice_holder.derive_keys_for_shared_account(&derivation_seed); + let group_npk = alice_keys.generate_nullifier_public_key(); + let group_vpk = alice_keys.generate_viewing_public_key(); + let group_id = AccountId::for_regular_private_account(&group_npk, 0); + + // Alice distributes the GMS to Bob via the real seal/unseal handshake, not by handing + // over key material directly. + let bob_sealing_keys = SecretSpendingKey([9_u8; 32]).produce_private_key_holder(None); + let bob_sealing_vpk = bob_sealing_keys.generate_viewing_public_key(); + let bob_sealing_vsk = bob_sealing_keys.viewing_secret_key; + let sealed_gms = alice_holder.seal_for(&SealingPublicKey::from_bytes( + bob_sealing_vpk.to_bytes().to_vec(), + )); + let bob_holder = + GroupKeyHolder::unseal(&sealed_gms, &bob_sealing_vsk).expect("Bob must unseal the GMS"); + + // Bob independently re-derives the same shared-account keys from the unsealed GMS. + let bob_keys = bob_holder.derive_keys_for_shared_account(&derivation_seed); + let bob_nsk = bob_keys.nullifier_secret_key; + assert_eq!( + bob_keys.generate_nullifier_public_key(), + group_npk, + "Bob must derive the identical npk as Alice from the shared GMS" + ); + + // Alice shields tokens into the group-owned holding (mirrors `shielded_token_transfer`, + // parameterized by the group's npk/vpk instead of a personal one). + let sender_id = Ids::holder(); + let sender_account = state.get_account_by_id(sender_id); + let sender_nonce = sender_account.nonce; + let sender_pre = AccountWithMetadata::new(sender_account, true, sender_id); + let group_pre_shield = AccountWithMetadata::new(Account::default(), false, group_id); + + let shield_secret = SharedSecretKey::encapsulate_deterministic(&group_vpk, &[0u8; 32], 0).0; + let shield_instruction = token_core::Instruction::Transfer { + amount_to_transfer: shield_amount, + }; + let (shield_output, shield_proof) = execute_and_prove( + vec![sender_pre, group_pre_shield], + Program::serialize_instruction(shield_instruction).unwrap(), + vec![ + InputAccountIdentity::Public, + InputAccountIdentity::PrivateUnauthorized { + epk: EphemeralPublicKey(Vec::new()), + view_tag: EncryptedAccountData::compute_view_tag(&group_npk, &group_vpk), + npk: group_npk, + ssk: shield_secret, + identifier: 0, + }, + ], + &token_program().into(), + ) + .unwrap(); + let shield_message = + Message::try_from_circuit_output(vec![sender_id], vec![sender_nonce], shield_output) + .unwrap(); + let shield_witness = + WitnessSet::for_message(&shield_message, shield_proof, &[&Keys::holder_key()]); + let shield_tx = PrivacyPreservingTransaction::new(shield_message, shield_witness); + state + .transition_from_privacy_preserving_transaction(&shield_tx, 0, 0) + .unwrap(); + + let group_account = Account { + program_owner: Ids::token_program(), + balance: 0, + data: Data::from(&TokenHolding::Fungible { + definition_id: Ids::token_definition(), + balance: shield_amount, + }), + nonce: Nonce::private_account_nonce_init(&group_id), + }; + let group_commitment = Commitment::new(&group_id, &group_account); + assert!(state.get_proof_for_commitment(&group_commitment).is_some()); + + // Bob — who never touched Alice's `GroupKeyHolder` object, only the sealed GMS — burns + // from the group-owned holding using his independently derived nsk. + let membership_proof = state + .get_proof_for_commitment(&group_commitment) + .expect("group holding's commitment must be in the set"); + let burn_shared_secret = + SharedSecretKey::encapsulate_deterministic(&group_vpk, &[0u8; 32], 0).0; + + let definition_pre = AccountWithMetadata::new( + state.get_account_by_id(Ids::token_definition()), + false, + Ids::token_definition(), + ); + let group_pre_burn = AccountWithMetadata::new(group_account, true, group_id); + + let burn_instruction = token_core::Instruction::Burn { + amount_to_burn: burn_amount, + }; + let (burn_output, burn_proof) = execute_and_prove( + vec![definition_pre, group_pre_burn], + Program::serialize_instruction(burn_instruction).unwrap(), + vec![ + InputAccountIdentity::Public, + InputAccountIdentity::PrivateAuthorizedUpdate { + epk: EphemeralPublicKey(Vec::new()), + view_tag: EncryptedAccountData::compute_view_tag(&group_npk, &group_vpk), + ssk: burn_shared_secret, + nsk: bob_nsk, + membership_proof, + identifier: 0, + }, + ], + &token_program().into(), + ) + .unwrap(); + + let burn_message = + Message::try_from_circuit_output(vec![Ids::token_definition()], vec![], burn_output) + .unwrap(); + let burn_witness = WitnessSet::for_message(&burn_message, burn_proof, &[]); + let burn_tx = PrivacyPreservingTransaction::new(burn_message, burn_witness); + state + .transition_from_privacy_preserving_transaction(&burn_tx, 0, 0) + .unwrap(); + + assert_eq!( + state.get_account_by_id(Ids::token_definition()), + Account { + program_owner: Ids::token_program(), + balance: 0_u128, + data: Data::from(&TokenDefinition::Fungible { + name: String::from("Gold"), + total_supply: 1_000_000_u128 - burn_amount, + metadata_id: None, + authority: Some(Ids::token_definition()), + }), + nonce: Nonce(0), + } + ); + + let group_nonce_after = + Nonce::private_account_nonce_init(&group_id).private_account_nonce_increment(&bob_nsk); + let new_group_account = Account { + program_owner: Ids::token_program(), + balance: 0, + data: Data::from(&TokenHolding::Fungible { + definition_id: Ids::token_definition(), + balance: shield_amount - burn_amount, + }), + nonce: group_nonce_after, + }; + assert!(state + .get_proof_for_commitment(&Commitment::new(&group_id, &new_group_account)) + .is_some()); +} + #[test] fn token_new_fungible_definition_with_authority() { let mut state = V03State::new();