From f268dca5bb0c6c6ec357a9284dc4ab6ca5586409 Mon Sep 17 00:00:00 2001 From: dave Date: Wed, 13 May 2026 15:07:11 +0000 Subject: [PATCH] huskies: merge 977 --- Cargo.lock | 717 +----------------- Cargo.toml | 2 +- crates/bft-json-crdt/Cargo.toml | 2 +- crates/bft-json-crdt/src/json_crdt/base.rs | 5 +- .../bft-json-crdt/src/json_crdt/signed_op.rs | 18 +- crates/bft-json-crdt/src/keypair.rs | 29 +- crates/bft-json-crdt/src/op.rs | 3 +- server/Cargo.toml | 3 +- server/src/crdt_state/ops.rs | 11 +- server/src/crdt_state/presence.rs | 1 - server/src/crdt_state/state/init.rs | 10 +- server/src/crdt_state/state/mod.rs | 3 +- server/src/crdt_sync/dispatch/tests.rs | 3 +- server/src/node_identity.rs | 10 +- 14 files changed, 59 insertions(+), 758 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 443047d9..8b0a8e7d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -41,18 +41,6 @@ dependencies = [ "cpufeatures 0.2.17", ] -[[package]] -name = "ahash" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - [[package]] name = "aho-corasick" version = "1.1.4" @@ -130,123 +118,6 @@ version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70e0a5f99dfebb87bb342d0f53bb92c81842e100bbb915223e38349580e5441d" -[[package]] -name = "ark-ec" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" -dependencies = [ - "ark-ff", - "ark-poly", - "ark-serialize", - "ark-std", - "derivative", - "hashbrown 0.13.2", - "itertools 0.10.5", - "num-traits", - "zeroize", -] - -[[package]] -name = "ark-ff" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" -dependencies = [ - "ark-ff-asm", - "ark-ff-macros", - "ark-serialize", - "ark-std", - "derivative", - "digest 0.10.7", - "itertools 0.10.5", - "num-bigint", - "num-traits", - "paste", - "rustc_version", - "zeroize", -] - -[[package]] -name = "ark-ff-asm" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" -dependencies = [ - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ark-ff-macros" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" -dependencies = [ - "num-bigint", - "num-traits", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ark-poly" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" -dependencies = [ - "ark-ff", - "ark-serialize", - "ark-std", - "derivative", - "hashbrown 0.13.2", -] - -[[package]] -name = "ark-secp256r1" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3975a01b0a6e3eae0f72ec7ca8598a6620fc72fa5981f6f5cca33b7cd788f633" -dependencies = [ - "ark-ec", - "ark-ff", - "ark-std", -] - -[[package]] -name = "ark-serialize" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" -dependencies = [ - "ark-serialize-derive", - "ark-std", - "digest 0.10.7", - "num-bigint", -] - -[[package]] -name = "ark-serialize-derive" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ark-std" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" -dependencies = [ - "num-traits", - "rand 0.8.6", -] - [[package]] name = "arrayref" version = "0.3.9" @@ -356,12 +227,6 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" -[[package]] -name = "auto_ops" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7460f7dd8e100147b82a63afca1a20eb6c231ee36b90ba7272e14951cb58af59" - [[package]] name = "autocfg" version = "1.5.0" @@ -401,12 +266,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "base16ct" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" - [[package]] name = "base64" version = "0.22.1" @@ -419,12 +278,6 @@ version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" -[[package]] -name = "bech32" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" - [[package]] name = "bft-crdt-derive" version = "0.1.0" @@ -443,7 +296,7 @@ dependencies = [ "bft-crdt-derive", "colored", "criterion", - "fastcrypto", + "ed25519-dalek", "indexmap 2.14.0", "rand 0.9.4", "random_color", @@ -453,30 +306,6 @@ dependencies = [ "sha2 0.11.0", ] -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - -[[package]] -name = "bitcoin-private" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73290177011694f38ec25e165d0387ab7ea749a4b81cd4c80dae5988229f7a57" - -[[package]] -name = "bitcoin_hashes" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d7066118b13d4b20b23645932dfb3a81ce7e29f95726c2036fa33cd7b092501" -dependencies = [ - "bitcoin-private", -] - [[package]] name = "bitflags" version = "1.3.2" @@ -498,15 +327,6 @@ version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d084b0137aaa901caf9f1e8b21daa6aa24d41cd806e111335541eff9683bd6" -[[package]] -name = "blake2" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" -dependencies = [ - "digest 0.10.7", -] - [[package]] name = "blake3" version = "1.8.5" @@ -521,15 +341,6 @@ dependencies = [ "cpufeatures 0.3.0", ] -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "generic-array", -] - [[package]] name = "block-buffer" version = "0.10.4" @@ -557,24 +368,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "blst" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcdb4c7013139a150f9fc55d123186dbfaba0d912817466282c73ac49e71fb45" -dependencies = [ - "cc", - "glob", - "threadpool", - "zeroize", -] - -[[package]] -name = "bs58" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" - [[package]] name = "bs58" version = "0.5.1" @@ -861,21 +654,6 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - -[[package]] -name = "convert_case" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "core-foundation" version = "0.9.4" @@ -1019,18 +797,6 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" -[[package]] -name = "crypto-bigint" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" -dependencies = [ - "generic-array", - "rand_core 0.6.4", - "subtle", - "zeroize", -] - [[package]] name = "crypto-common" version = "0.1.7" @@ -1097,19 +863,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "curve25519-dalek-ng" -version = "4.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c359b7249347e46fb28804470d071c921156ad62b3eef5d34e2ba867533dec8" -dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.6.4", - "subtle-ng", - "zeroize", -] - [[package]] name = "darling" version = "0.23.0" @@ -1210,17 +963,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "der" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" -dependencies = [ - "const-oid 0.9.6", - "pem-rfc7468 0.6.0", - "zeroize", -] - [[package]] name = "der" version = "0.7.10" @@ -1228,7 +970,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ "const-oid 0.9.6", - "pem-rfc7468 0.7.0", + "pem-rfc7468", "zeroize", ] @@ -1253,19 +995,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "derive_more" -version = "0.99.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" -dependencies = [ - "convert_case 0.4.0", - "proc-macro2", - "quote", - "rustc_version", - "syn 2.0.117", -] - [[package]] name = "derive_more" version = "1.0.0" @@ -1308,15 +1037,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array", -] - [[package]] name = "digest" version = "0.10.7" @@ -1376,46 +1096,17 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" -[[package]] -name = "ecdsa" -version = "0.16.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" -dependencies = [ - "der 0.7.10", - "digest 0.10.7", - "elliptic-curve", - "rfc6979", - "signature", - "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", + "pkcs8", "serde", "signature", ] -[[package]] -name = "ed25519-consensus" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c8465edc8ee7436ffea81d21a019b16676ee3db267aa8d5a8d729581ecf998b" -dependencies = [ - "curve25519-dalek-ng", - "hex", - "rand_core 0.6.4", - "serde", - "sha2 0.9.9", - "thiserror 1.0.69", - "zeroize", -] - [[package]] name = "ed25519-dalek" version = "2.2.0" @@ -1440,26 +1131,6 @@ dependencies = [ "serde", ] -[[package]] -name = "elliptic-curve" -version = "0.13.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" -dependencies = [ - "base16ct", - "crypto-bigint", - "digest 0.10.7", - "ff", - "generic-array", - "group", - "pem-rfc7468 0.7.0", - "pkcs8 0.10.2", - "rand_core 0.6.4", - "sec1", - "subtle", - "zeroize", -] - [[package]] name = "encoding_rs" version = "0.8.35" @@ -1578,85 +1249,12 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "fastcrypto" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e06674cac3bf7ec9a951971285e6051a45273dc4e265cca27c02a0d4ebcb46f8" -dependencies = [ - "ark-ec", - "ark-ff", - "ark-secp256r1", - "ark-serialize", - "auto_ops", - "base64ct", - "bech32", - "bincode", - "blake2", - "blst", - "bs58 0.4.0", - "curve25519-dalek-ng", - "derive_more 0.99.20", - "digest 0.10.7", - "ecdsa", - "ed25519-consensus", - "elliptic-curve", - "fastcrypto-derive", - "generic-array", - "hex", - "hex-literal", - "hkdf", - "lazy_static", - "num-bigint", - "once_cell", - "p256", - "rand 0.8.6", - "readonly", - "rfc6979", - "rsa 0.8.2", - "schemars 0.8.22", - "secp256k1", - "serde", - "serde_json", - "serde_with", - "sha2 0.10.9", - "sha3", - "signature", - "static_assertions", - "thiserror 1.0.69", - "tokio", - "typenum", - "zeroize", -] - -[[package]] -name = "fastcrypto-derive" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c0c2af2157f416cb885e11d36cd0de2753f6d5384752d364075c835f5f8f891" -dependencies = [ - "convert_case 0.6.0", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "fastrand" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" -[[package]] -name = "ff" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" -dependencies = [ - "rand_core 0.6.4", - "subtle", -] - [[package]] name = "fiat-crypto" version = "0.2.9" @@ -1881,10 +1479,8 @@ version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ - "serde", "typenum", "version_check", - "zeroize", ] [[package]] @@ -1927,12 +1523,6 @@ dependencies = [ "wasip3", ] -[[package]] -name = "glob" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" - [[package]] name = "globset" version = "0.4.18" @@ -1971,17 +1561,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "group" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" -dependencies = [ - "ff", - "rand_core 0.6.4", - "subtle", -] - [[package]] name = "growable-bloom-filter" version = "2.1.1" @@ -2030,15 +1609,6 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -[[package]] -name = "hashbrown" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" -dependencies = [ - "ahash", -] - [[package]] name = "hashbrown" version = "0.15.5" @@ -2116,12 +1686,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hex-literal" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" - [[package]] name = "hkdf" version = "0.12.4" @@ -2248,7 +1812,6 @@ dependencies = [ "chrono-tz", "ed25519-dalek", "eventsource-stream", - "fastcrypto", "filetime", "futures", "hmac 0.13.0", @@ -2749,15 +2312,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "keccak" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" -dependencies = [ - "cpufeatures 0.2.17", -] - [[package]] name = "konst" version = "0.3.17" @@ -3110,7 +2664,7 @@ dependencies = [ "aquamarine", "as_variant", "async-trait", - "bs58 0.5.1", + "bs58", "byteorder", "cfg-if", "ctr", @@ -3428,16 +2982,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] - [[package]] name = "num-bigint-dig" version = "0.8.6" @@ -3544,18 +3088,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" -[[package]] -name = "p256" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" -dependencies = [ - "ecdsa", - "elliptic-curve", - "primeorder", - "sha2 0.10.9", -] - [[package]] name = "page_size" version = "0.6.0" @@ -3595,12 +3127,6 @@ dependencies = [ "windows-link 0.2.1", ] -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - [[package]] name = "pbkdf2" version = "0.12.2" @@ -3611,15 +3137,6 @@ dependencies = [ "hmac 0.12.1", ] -[[package]] -name = "pem-rfc7468" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d159833a9105500e0398934e205e0773f0b27529557134ecfc51c27646adac" -dependencies = [ - "base64ct", -] - [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -3697,37 +3214,15 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" -[[package]] -name = "pkcs1" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eff33bdbdfc54cc98a2eca766ebdec3e1b8fb7387523d5c9c9a2891da856f719" -dependencies = [ - "der 0.6.1", - "pkcs8 0.9.0", - "spki 0.6.0", - "zeroize", -] - [[package]] name = "pkcs1" version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" dependencies = [ - "der 0.7.10", - "pkcs8 0.10.2", - "spki 0.7.3", -] - -[[package]] -name = "pkcs8" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" -dependencies = [ - "der 0.6.1", - "spki 0.6.0", + "der", + "pkcs8", + "spki", ] [[package]] @@ -3736,8 +3231,8 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ - "der 0.7.10", - "spki 0.7.3", + "der", + "spki", ] [[package]] @@ -3901,15 +3396,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "primeorder" -version = "0.13.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" -dependencies = [ - "elliptic-curve", -] - [[package]] name = "proc-macro-crate" version = "3.5.0" @@ -4179,17 +3665,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "readonly" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2a62d85ed81ca5305dc544bd42c8804c5060b78ffa5ad3c64b0fb6a8c13d062" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - [[package]] name = "redox_syscall" version = "0.5.18" @@ -4343,16 +3818,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "rfc6979" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" -dependencies = [ - "hmac 0.12.1", - "subtle", -] - [[package]] name = "rfc7239" version = "0.1.3" @@ -4395,27 +3860,6 @@ dependencies = [ "serde", ] -[[package]] -name = "rsa" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55a77d189da1fee555ad95b7e50e7457d91c0e089ec68ca69ad2989413bbdab4" -dependencies = [ - "byteorder", - "digest 0.10.7", - "num-bigint-dig", - "num-integer", - "num-iter", - "num-traits", - "pkcs1 0.4.1", - "pkcs8 0.9.0", - "rand_core 0.6.4", - "sha2 0.10.9", - "signature", - "subtle", - "zeroize", -] - [[package]] name = "rsa" version = "0.9.10" @@ -4427,11 +3871,11 @@ dependencies = [ "num-bigint-dig", "num-integer", "num-traits", - "pkcs1 0.7.5", - "pkcs8 0.10.2", + "pkcs1", + "pkcs8", "rand_core 0.6.4", "signature", - "spki 0.7.3", + "spki", "subtle", "zeroize", ] @@ -4603,7 +4047,7 @@ checksum = "146ace2cd59b60ec80d3e801a84e7e6a91e3e01d18a9f5d896ea7ca16a6b8e08" dependencies = [ "base64", "ed25519-dalek", - "pkcs8 0.10.2", + "pkcs8", "rand 0.8.6", "ruma-common", "serde_json", @@ -4793,18 +4237,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "schemars" -version = "0.8.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" -dependencies = [ - "dyn-clone", - "schemars_derive", - "serde", - "serde_json", -] - [[package]] name = "schemars" version = "0.9.0" @@ -4829,18 +4261,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "schemars_derive" -version = "0.8.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" -dependencies = [ - "proc-macro2", - "quote", - "serde_derive_internals", - "syn 2.0.117", -] - [[package]] name = "scopeguard" version = "1.2.0" @@ -4858,40 +4278,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "sec1" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" -dependencies = [ - "base16ct", - "der 0.7.10", - "generic-array", - "pkcs8 0.10.2", - "subtle", - "zeroize", -] - -[[package]] -name = "secp256k1" -version = "0.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" -dependencies = [ - "bitcoin_hashes", - "rand 0.8.6", - "secp256k1-sys", -] - -[[package]] -name = "secp256k1-sys" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4473013577ec77b4ee3668179ef1186df3146e2cf2d927bd200974c6fe60fd99" -dependencies = [ - "cc", -] - [[package]] name = "security-framework" version = "3.7.0" @@ -4972,17 +4358,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "serde_derive_internals" -version = "0.29.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - [[package]] name = "serde_html_form" version = "0.2.8" @@ -5049,7 +4424,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e72c1c2cb7b223fafb600a619537a871c2818583d619401b785e7c0b746ccde2" dependencies = [ "base64", - "bs58 0.5.1", + "bs58", "chrono", "hex", "indexmap 1.9.3", @@ -5120,19 +4495,6 @@ dependencies = [ "digest 0.11.3", ] -[[package]] -name = "sha2" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" -dependencies = [ - "block-buffer 0.9.0", - "cfg-if", - "cpufeatures 0.2.17", - "digest 0.9.0", - "opaque-debug", -] - [[package]] name = "sha2" version = "0.10.9" @@ -5155,16 +4517,6 @@ dependencies = [ "digest 0.11.3", ] -[[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", -] - [[package]] name = "sharded-slab" version = "0.1.7" @@ -5292,16 +4644,6 @@ dependencies = [ "lock_api", ] -[[package]] -name = "spki" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" -dependencies = [ - "base64ct", - "der 0.6.1", -] - [[package]] name = "spki" version = "0.7.3" @@ -5309,7 +4651,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", - "der 0.7.10", + "der", ] [[package]] @@ -5425,7 +4767,7 @@ dependencies = [ "memchr", "percent-encoding", "rand 0.8.6", - "rsa 0.9.10", + "rsa", "sha1 0.10.6", "sha2 0.10.9", "smallvec", @@ -5513,12 +4855,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - [[package]] name = "string_cache" version = "0.8.9" @@ -5576,12 +4912,6 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" -[[package]] -name = "subtle-ng" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" - [[package]] name = "syn" version = "1.0.109" @@ -5718,15 +5048,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "threadpool" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" -dependencies = [ - "num_cpus", -] - [[package]] name = "time" version = "0.3.47" @@ -6180,12 +5501,6 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" -[[package]] -name = "unicode-segmentation" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" - [[package]] name = "unicode-xid" version = "0.2.6" diff --git a/Cargo.toml b/Cargo.toml index 9e0c886f..44343dd6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ poem = { version = "3", features = ["websocket", "test"] } portable-pty = "0.9.0" reqwest = { version = "0.13.3", features = ["json", "stream"] } rust-embed = "8" -fastcrypto = "0.1.9" +ed25519-dalek = { version = "2", default-features = false, features = ["rand_core"] } indexmap = { version = "2.14.0", features = ["serde"] } rand = "0.9" serde = { version = "1", features = ["derive"] } diff --git a/crates/bft-json-crdt/Cargo.toml b/crates/bft-json-crdt/Cargo.toml index 998ef739..f006b563 100644 --- a/crates/bft-json-crdt/Cargo.toml +++ b/crates/bft-json-crdt/Cargo.toml @@ -16,7 +16,7 @@ bft = [] [dependencies] bft-crdt-derive = { path = "bft-crdt-derive" } colored = "3" -fastcrypto = { workspace = true } +ed25519-dalek = { workspace = true } indexmap = { workspace = true, features = ["serde"] } rand = { workspace = true } random_color = "1" diff --git a/crates/bft-json-crdt/src/json_crdt/base.rs b/crates/bft-json-crdt/src/json_crdt/base.rs index 49e82e10..154d4435 100644 --- a/crates/bft-json-crdt/src/json_crdt/base.rs +++ b/crates/bft-json-crdt/src/json_crdt/base.rs @@ -2,8 +2,7 @@ use std::collections::{HashMap, HashSet}; -use fastcrypto::ed25519::Ed25519KeyPair; -use fastcrypto::traits::KeyPair; +use crate::keypair::Ed25519KeyPair; use crate::debug::DebugView; use crate::keypair::SignedDigest; @@ -36,7 +35,7 @@ impl BaseCrdt { /// routing messages to the right BaseCRDT. Usually you should just make a single /// struct that contains all the state you need. pub fn new(keypair: &Ed25519KeyPair) -> Self { - let id = keypair.public().0.to_bytes(); + let id = keypair.verifying_key().to_bytes(); Self { id, doc: T::new(id, vec![]), diff --git a/crates/bft-json-crdt/src/json_crdt/signed_op.rs b/crates/bft-json-crdt/src/json_crdt/signed_op.rs index 11c05064..f0a3e103 100644 --- a/crates/bft-json-crdt/src/json_crdt/signed_op.rs +++ b/crates/bft-json-crdt/src/json_crdt/signed_op.rs @@ -1,10 +1,7 @@ //! [`SignedOp`], [`OpState`], and the causal queue capacity constant. -use fastcrypto::traits::VerifyingKey; -use fastcrypto::{ - ed25519::{Ed25519KeyPair, Ed25519PublicKey, Ed25519Signature}, - traits::{KeyPair, ToFromBytes}, -}; +use crate::keypair::{Ed25519KeyPair, Ed25519PublicKey, Ed25519Signature}; +use ed25519_dalek::Verifier as _; use serde::{Deserialize, Serialize}; use serde_with::{serde_as, Bytes}; @@ -107,16 +104,15 @@ impl SignedOp { /// Sign this digest with the given keypair. Shouldn't need to be called manually, /// just use [`SignedOp::from_op`] instead fn sign_digest(&mut self, keypair: &Ed25519KeyPair) { - self.signed_digest = sign(keypair, &self.digest()).sig.to_bytes() + self.signed_digest = sign(keypair, &self.digest()).to_bytes() } /// Ensure digest was actually signed by the author it claims to be signed by pub fn is_valid_digest(&self) -> bool { let digest = Ed25519Signature::from_bytes(&self.signed_digest); - let pubkey = Ed25519PublicKey::from_bytes(&self.author()); - match (digest, pubkey) { - (Ok(digest), Ok(pubkey)) => pubkey.verify(&self.digest(), &digest).is_ok(), - (_, _) => false, + match Ed25519PublicKey::from_bytes(&self.author()) { + Ok(pubkey) => pubkey.verify(&self.digest(), &digest).is_ok(), + Err(_) => false, } } @@ -126,7 +122,7 @@ impl SignedOp { keypair: &Ed25519KeyPair, depends_on: Vec, ) -> Self { - let author = keypair.public().0.to_bytes(); + let author = keypair.verifying_key().to_bytes(); let mut new = Self { inner: Op { content: value.content.map(|c| c.view()), diff --git a/crates/bft-json-crdt/src/keypair.rs b/crates/bft-json-crdt/src/keypair.rs index b889eb37..23094f78 100644 --- a/crates/bft-json-crdt/src/keypair.rs +++ b/crates/bft-json-crdt/src/keypair.rs @@ -1,21 +1,25 @@ //! Ed25519 keypair utilities and type aliases for node identity and signing. //! //! Provides the [`AuthorId`] and [`SignedDigest`] type aliases, a SHA-256 helper, -//! and convenience wrappers around the `fastcrypto` Ed25519 primitives used +//! and convenience wrappers around the `ed25519-dalek` Ed25519 primitives used //! throughout the CRDT codebase. -use fastcrypto::traits::VerifyingKey; -pub use fastcrypto::{ - ed25519::{ - Ed25519KeyPair, Ed25519PublicKey, Ed25519Signature, ED25519_PUBLIC_KEY_LENGTH, - ED25519_SIGNATURE_LENGTH, - }, - traits::{KeyPair, Signer, ToFromBytes}, - // Verifier, -}; -use rand::RngCore as _; +use ed25519_dalek::Signer as _; +use ed25519_dalek::Verifier as _; use sha2::{Digest, Sha256}; +/// Ed25519 signing key (private + public pair). +pub type Ed25519KeyPair = ed25519_dalek::SigningKey; +/// Ed25519 verifying (public) key. +pub type Ed25519PublicKey = ed25519_dalek::VerifyingKey; +/// Ed25519 signature. +pub type Ed25519Signature = ed25519_dalek::Signature; + +/// Length of an Ed25519 public key in bytes. +pub const ED25519_PUBLIC_KEY_LENGTH: usize = 32; +/// Length of an Ed25519 signature in bytes. +pub const ED25519_SIGNATURE_LENGTH: usize = 64; + /// Represents the ID of a unique node. An Ed25519 public key pub type AuthorId = [u8; ED25519_PUBLIC_KEY_LENGTH]; @@ -49,9 +53,10 @@ pub fn sha256(input: String) -> [u8; 32] { /// Generate a random Ed25519 keypair from OS rng pub fn make_keypair() -> Ed25519KeyPair { + use rand::RngCore as _; let mut seed = [0u8; 32]; rand::rng().fill_bytes(&mut seed); - Ed25519KeyPair::from_bytes(&seed).expect("32-byte seed always yields a valid Ed25519 keypair") + Ed25519KeyPair::from_bytes(&seed) } /// Sign a byte array diff --git a/crates/bft-json-crdt/src/op.rs b/crates/bft-json-crdt/src/op.rs index 58f82283..65243ef6 100644 --- a/crates/bft-json-crdt/src/op.rs +++ b/crates/bft-json-crdt/src/op.rs @@ -6,8 +6,7 @@ use crate::debug::{debug_path_mismatch, debug_type_mismatch}; use crate::json_crdt::{CrdtNode, CrdtNodeFromValue, IntoCrdtNode, JsonValue, SignedOp}; -use crate::keypair::{sha256, AuthorId}; -use fastcrypto::ed25519::Ed25519KeyPair; +use crate::keypair::{sha256, AuthorId, Ed25519KeyPair}; use serde::{Deserialize, Serialize}; use std::fmt::Debug; diff --git a/server/Cargo.toml b/server/Cargo.toml index 80493fa2..52390ec8 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -45,8 +45,7 @@ sqlx = { workspace = true } wait-timeout = "0.2.1" bft-json-crdt = { path = "../crates/bft-json-crdt", default-features = false, features = ["bft"] } source-map-gen = { path = "../crates/source-map-gen" } -ed25519-dalek = { version = "2", features = ["rand_core"] } -fastcrypto = { workspace = true } +ed25519-dalek = { workspace = true } rand = { workspace = true } indexmap = { workspace = true, features = ["serde"] } diff --git a/server/src/crdt_state/ops.rs b/server/src/crdt_state/ops.rs index 9e778fad..4b2c6e0f 100644 --- a/server/src/crdt_state/ops.rs +++ b/server/src/crdt_state/ops.rs @@ -198,9 +198,8 @@ mod tests { use super::super::write::write_item_str; use super::*; use bft_json_crdt::json_crdt::OpState; - use bft_json_crdt::keypair::make_keypair; + use bft_json_crdt::keypair::{Ed25519KeyPair, make_keypair}; use bft_json_crdt::op::ROOT_ID; - use fastcrypto::ed25519::Ed25519KeyPair; use serde_json::json; #[test] @@ -438,8 +437,6 @@ mod tests { #[test] fn delta_sync_multi_author() { - use fastcrypto::traits::KeyPair; - let kp_a = make_keypair(); let kp_b = make_keypair(); let mut crdt_a = BaseCrdt::::new(&kp_a); @@ -454,7 +451,7 @@ mod tests { // Peer has seen all of A's ops but none of B's. let mut peer_clock = VectorClock::new(); - let author_a_hex = hex::encode(&kp_a.public().0.to_bytes()); + let author_a_hex = hex::encode(&kp_a.verifying_key().to_bytes()); peer_clock.insert(author_a_hex, 30); let delta = local_ops_since(&all_ops, &peer_clock); @@ -468,14 +465,12 @@ mod tests { #[test] fn build_vector_clock_from_ops() { - use fastcrypto::traits::KeyPair; - let kp = make_keypair(); let mut crdt = BaseCrdt::::new(&kp); let ops = make_ops(&kp, &mut crdt, 10, "631_vc"); let clock = build_clock(&ops); - let author_hex = hex::encode(&kp.public().0.to_bytes()); + let author_hex = hex::encode(&kp.verifying_key().to_bytes()); assert_eq!(clock.len(), 1, "single author should produce 1 clock entry"); assert_eq!(clock[&author_hex], 10, "clock should show 10 ops"); diff --git a/server/src/crdt_state/presence.rs b/server/src/crdt_state/presence.rs index 77b8551a..44c93cad 100644 --- a/server/src/crdt_state/presence.rs +++ b/server/src/crdt_state/presence.rs @@ -6,7 +6,6 @@ use super::read::read_item; use bft_json_crdt::json_crdt::*; use bft_json_crdt::lww_crdt::LwwRegisterCrdt; use bft_json_crdt::op::ROOT_ID; -use fastcrypto::traits::{Signer, ToFromBytes}; use serde_json::json; use super::state::{apply_and_persist, get_crdt, rebuild_node_index}; diff --git a/server/src/crdt_state/state/init.rs b/server/src/crdt_state/state/init.rs index c91cfcfa..64c3d00e 100644 --- a/server/src/crdt_state/state/init.rs +++ b/server/src/crdt_state/state/init.rs @@ -10,9 +10,7 @@ use std::path::Path; use std::sync::Mutex; use bft_json_crdt::json_crdt::{BaseCrdt, CrdtNode, JsonValue, SignedOp}; -use bft_json_crdt::keypair::make_keypair; -use fastcrypto::ed25519::Ed25519KeyPair; -use fastcrypto::traits::ToFromBytes; +use bft_json_crdt::keypair::{Ed25519KeyPair, make_keypair}; use sqlx::SqlitePool; use sqlx::sqlite::SqliteConnectOptions; use tokio::sync::{broadcast, mpsc}; @@ -192,14 +190,14 @@ async fn load_or_create_keypair(pool: &SqlitePool) -> Result::try_into(seed) { + return Ok(Ed25519KeyPair::from_bytes(&arr)); } slog!("[crdt] Stored keypair invalid, regenerating"); } let kp = make_keypair(); - let seed = kp.as_bytes().to_vec(); + let seed = kp.to_bytes().to_vec(); sqlx::query("INSERT INTO crdt_node_identity (id, seed) VALUES (1, ?1) ON CONFLICT(id) DO UPDATE SET seed = excluded.seed") .bind(&seed) .execute(pool) diff --git a/server/src/crdt_state/state/mod.rs b/server/src/crdt_state/state/mod.rs index dcceb3f6..2de501e6 100644 --- a/server/src/crdt_state/state/mod.rs +++ b/server/src/crdt_state/state/mod.rs @@ -10,8 +10,7 @@ use std::collections::{HashMap, HashSet}; use std::sync::{Mutex, OnceLock}; use bft_json_crdt::json_crdt::{BaseCrdt, SignedOp}; -use bft_json_crdt::keypair::make_keypair; -use fastcrypto::ed25519::Ed25519KeyPair; +use bft_json_crdt::keypair::{Ed25519KeyPair, make_keypair}; use tokio::sync::{broadcast, mpsc}; use super::VectorClock; diff --git a/server/src/crdt_sync/dispatch/tests.rs b/server/src/crdt_sync/dispatch/tests.rs index 8319499e..6348206f 100644 --- a/server/src/crdt_sync/dispatch/tests.rs +++ b/server/src/crdt_sync/dispatch/tests.rs @@ -604,7 +604,6 @@ fn v2_delta_sync_via_clock_exchange() { use bft_json_crdt::json_crdt::BaseCrdt; use bft_json_crdt::keypair::make_keypair; use bft_json_crdt::op::ROOT_ID; - use fastcrypto::traits::KeyPair; use serde_json::json; use crate::crdt_state::PipelineDoc; @@ -641,7 +640,7 @@ fn v2_delta_sync_via_clock_exchange() { assert_eq!(crdt_b.doc.items.view().len(), 3); // Build B's clock. - let author_a_hex = crate::crdt_state::hex::encode(&kp_a.public().0.to_bytes()); + let author_a_hex = crate::crdt_state::hex::encode(&kp_a.verifying_key().to_bytes()); let mut clock_b = std::collections::HashMap::new(); clock_b.insert(author_a_hex.clone(), 3u64); diff --git a/server/src/node_identity.rs b/server/src/node_identity.rs index 2e493d09..c02f4347 100644 --- a/server/src/node_identity.rs +++ b/server/src/node_identity.rs @@ -41,8 +41,6 @@ //! `verify_challenge` primitive but leaves the allow-list to story 480. use bft_json_crdt::keypair::{Ed25519KeyPair, Ed25519Signature, sign}; -use ed25519_dalek::SigningKey; -use fastcrypto::traits::{KeyPair, ToFromBytes}; use rand::RngCore; use std::sync::OnceLock; @@ -84,7 +82,7 @@ pub fn generate_challenge() -> ChallengeHex { /// encoding steps. pub fn sign_challenge(keypair: &Ed25519KeyPair, challenge: &str) -> SignatureHex { let sig: Ed25519Signature = sign(keypair, challenge.as_bytes()); - hex_encode(sig.as_bytes()) + hex_encode(&sig.to_bytes()) } // ── Verification ────────────────────────────────────────────────────── @@ -143,7 +141,7 @@ pub fn verify_message_strict(pubkey_hex: &str, message: &[u8], signature_hex: &s /// This is the same value written to the CRDT `claimed_by` and `node_id` /// registers, so it is the canonical node identity across all subsystems. pub fn public_key_hex(keypair: &Ed25519KeyPair) -> String { - hex_encode(keypair.public().as_bytes()) + hex_encode(&keypair.verifying_key().to_bytes()) } // ── File-based keypair persistence (ed25519-dalek) ──────────────────────── @@ -181,12 +179,12 @@ pub fn load_or_create_keypair_file(path: &std::path::Path) -> std::io::Result