Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5c0f8a7dc8 | |||
| f94acf95b2 | |||
| ae607d300a | |||
| f895cbd91d | |||
| ff253aed1f | |||
| d36bcad11b | |||
| 77d1f2b845 | |||
| 19661bc172 |
Generated
+220
-30
@@ -1446,6 +1446,17 @@ version = "0.8.7"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-models"
|
||||||
|
version = "0.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "94950e87ea550d6d68f1993f3e7bebc8cb7235157bff84337d46195c3aa0b3f0"
|
||||||
|
dependencies = [
|
||||||
|
"hax-lib",
|
||||||
|
"pastey",
|
||||||
|
"rand 0.9.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cosmos-sdk-proto"
|
name = "cosmos-sdk-proto"
|
||||||
version = "0.26.1"
|
version = "0.26.1"
|
||||||
@@ -3150,6 +3161,43 @@ dependencies = [
|
|||||||
"hashbrown 0.15.2",
|
"hashbrown 0.15.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hax-lib"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a89999d4446ba7d86c777bc6a30c106b9bf60d12eb1952242af5d1d7cb33943d"
|
||||||
|
dependencies = [
|
||||||
|
"hax-lib-macros",
|
||||||
|
"num-bigint",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hax-lib-macros"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "704a31fb12a8c50243e8d4c88d006f64852822b0e24488a0de9986803a661792"
|
||||||
|
dependencies = [
|
||||||
|
"hax-lib-macros-types",
|
||||||
|
"proc-macro-error2",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.98",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hax-lib-macros-types"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f302d2a43ba5888c61454ffeb8719dc43e7c0e83082d0fe302ac82d8d898b075"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"uuid",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hdrhistogram"
|
name = "hdrhistogram"
|
||||||
version = "7.5.4"
|
version = "7.5.4"
|
||||||
@@ -3257,7 +3305,7 @@ dependencies = [
|
|||||||
"idna",
|
"idna",
|
||||||
"ipnet",
|
"ipnet",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rand 0.9.0",
|
"rand 0.9.1",
|
||||||
"ring",
|
"ring",
|
||||||
"rustls 0.23.25",
|
"rustls 0.23.25",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
@@ -3282,7 +3330,7 @@ dependencies = [
|
|||||||
"moka",
|
"moka",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"rand 0.9.0",
|
"rand 0.9.1",
|
||||||
"resolv-conf",
|
"resolv-conf",
|
||||||
"rustls 0.23.25",
|
"rustls 0.23.25",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
@@ -4157,6 +4205,143 @@ version = "0.2.171"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
|
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libcrux-curve25519"
|
||||||
|
version = "0.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5514645ba1ee6c55dd71d62a50cc37ad8aab3f956826001aa8dad17482655c46"
|
||||||
|
dependencies = [
|
||||||
|
"libcrux-hacl-rs",
|
||||||
|
"libcrux-macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libcrux-ecdh"
|
||||||
|
version = "0.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c4fa67cad871d7be9175141b23a174b77536b039945c91b6a5a6d697acd6371"
|
||||||
|
dependencies = [
|
||||||
|
"libcrux-curve25519",
|
||||||
|
"libcrux-p256",
|
||||||
|
"rand 0.9.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libcrux-hacl-rs"
|
||||||
|
version = "0.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1134af11da3f24ae8d1a7e2b60ee871c9e3ffd3d8857deaeebab8088b005addd"
|
||||||
|
dependencies = [
|
||||||
|
"libcrux-macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libcrux-intrinsics"
|
||||||
|
version = "0.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5d3b41dcbc21a5fb7efbbb5af7405b2e79c4bfe443924e90b13afc0080318d31"
|
||||||
|
dependencies = [
|
||||||
|
"core-models",
|
||||||
|
"hax-lib",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libcrux-kem"
|
||||||
|
version = "0.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eefe0e9579f058b99995cbaf918de3cbab90c4d2dde544fe75247fb027ff5af9"
|
||||||
|
dependencies = [
|
||||||
|
"libcrux-ecdh",
|
||||||
|
"libcrux-ml-kem",
|
||||||
|
"libcrux-sha3",
|
||||||
|
"libcrux-traits",
|
||||||
|
"rand 0.9.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libcrux-macros"
|
||||||
|
version = "0.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ffd6aa2dcd5be681662001b81d493f1569c6d49a32361f470b0c955465cd0338"
|
||||||
|
dependencies = [
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.98",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libcrux-ml-kem"
|
||||||
|
version = "0.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5d368d3e8d6a74e277178d54921eca112a1e6b7837d7d8bc555091acb5d817f5"
|
||||||
|
dependencies = [
|
||||||
|
"hax-lib",
|
||||||
|
"libcrux-intrinsics",
|
||||||
|
"libcrux-platform",
|
||||||
|
"libcrux-secrets",
|
||||||
|
"libcrux-sha3",
|
||||||
|
"rand 0.9.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libcrux-p256"
|
||||||
|
version = "0.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b00d21690ebcc7ce1f242e6c4bdadfd8529f9cf2d7b961c0344c9bcb2c82f78f"
|
||||||
|
dependencies = [
|
||||||
|
"libcrux-hacl-rs",
|
||||||
|
"libcrux-macros",
|
||||||
|
"libcrux-sha2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libcrux-platform"
|
||||||
|
version = "0.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "db82d058aa76ea315a3b2092f69dfbd67ddb0e462038a206e1dcd73f058c0778"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libcrux-secrets"
|
||||||
|
version = "0.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "332737e629fe6ba7547f5c0f90559eac865d5dbecf98138ffae8f16ab8cbe33f"
|
||||||
|
dependencies = [
|
||||||
|
"hax-lib",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libcrux-sha2"
|
||||||
|
version = "0.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "91eed3bb0ae073f46ae03c83318013fba6e3302bf3292639417b68e908fec4bf"
|
||||||
|
dependencies = [
|
||||||
|
"libcrux-hacl-rs",
|
||||||
|
"libcrux-macros",
|
||||||
|
"libcrux-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libcrux-sha3"
|
||||||
|
version = "0.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "29d95de4257eafdfaf3bffecadb615219b0ca920c553722b3646d32dde76c797"
|
||||||
|
dependencies = [
|
||||||
|
"hax-lib",
|
||||||
|
"libcrux-intrinsics",
|
||||||
|
"libcrux-platform",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libcrux-traits"
|
||||||
|
version = "0.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0cdbf9591a39f04d6da6b9bad51ac58378604a80708c2173dadf92029891b9e2"
|
||||||
|
dependencies = [
|
||||||
|
"rand 0.9.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libm"
|
name = "libm"
|
||||||
version = "0.2.11"
|
version = "0.2.11"
|
||||||
@@ -6856,25 +7041,6 @@ dependencies = [
|
|||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nym-outfox"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"blake3",
|
|
||||||
"chacha20",
|
|
||||||
"chacha20poly1305",
|
|
||||||
"criterion",
|
|
||||||
"fastrand 2.3.0",
|
|
||||||
"getrandom 0.2.15",
|
|
||||||
"log",
|
|
||||||
"rand 0.8.5",
|
|
||||||
"rayon",
|
|
||||||
"sphinx-packet",
|
|
||||||
"thiserror 2.0.12",
|
|
||||||
"x25519-dalek",
|
|
||||||
"zeroize",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-outfox"
|
name = "nym-outfox"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -6893,6 +7059,25 @@ dependencies = [
|
|||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nym-outfox"
|
||||||
|
version = "0.2.0"
|
||||||
|
dependencies = [
|
||||||
|
"blake3",
|
||||||
|
"bs58",
|
||||||
|
"chacha20",
|
||||||
|
"chacha20poly1305",
|
||||||
|
"criterion",
|
||||||
|
"fastrand 2.3.0",
|
||||||
|
"getrandom 0.2.15",
|
||||||
|
"libcrux-kem",
|
||||||
|
"log",
|
||||||
|
"rand 0.9.1",
|
||||||
|
"rayon",
|
||||||
|
"thiserror 2.0.12",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-pemstore"
|
name = "nym-pemstore"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
@@ -7371,7 +7556,7 @@ name = "nym-sphinx-forwarding"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f"
|
source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nym-outfox 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)",
|
"nym-outfox 0.1.0",
|
||||||
"nym-sphinx-addressing 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)",
|
"nym-sphinx-addressing 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)",
|
||||||
"nym-sphinx-params 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)",
|
"nym-sphinx-params 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)",
|
||||||
"nym-sphinx-types 0.2.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)",
|
"nym-sphinx-types 0.2.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)",
|
||||||
@@ -7454,7 +7639,7 @@ dependencies = [
|
|||||||
name = "nym-sphinx-types"
|
name = "nym-sphinx-types"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nym-outfox 0.1.0",
|
"nym-outfox 0.2.0",
|
||||||
"sphinx-packet",
|
"sphinx-packet",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
]
|
]
|
||||||
@@ -7464,7 +7649,7 @@ name = "nym-sphinx-types"
|
|||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f"
|
source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nym-outfox 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)",
|
"nym-outfox 0.1.0",
|
||||||
"sphinx-packet",
|
"sphinx-packet",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
]
|
]
|
||||||
@@ -8318,6 +8503,12 @@ version = "1.0.15"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pastey"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b3a8cb46bdc156b1c90460339ae6bfd45ba0394e5effbaa640badb4987fdc261"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "peg"
|
name = "peg"
|
||||||
version = "0.8.4"
|
version = "0.8.4"
|
||||||
@@ -8638,7 +8829,7 @@ dependencies = [
|
|||||||
"hmac",
|
"hmac",
|
||||||
"md-5",
|
"md-5",
|
||||||
"memchr",
|
"memchr",
|
||||||
"rand 0.9.0",
|
"rand 0.9.1",
|
||||||
"sha2 0.10.9",
|
"sha2 0.10.9",
|
||||||
"stringprep",
|
"stringprep",
|
||||||
]
|
]
|
||||||
@@ -8889,7 +9080,7 @@ checksum = "b820744eb4dc9b57a3398183639c511b5a26d2ed702cedd3febaa1393caa22cc"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"getrandom 0.3.1",
|
"getrandom 0.3.1",
|
||||||
"rand 0.9.0",
|
"rand 0.9.1",
|
||||||
"ring",
|
"ring",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"rustls 0.23.25",
|
"rustls 0.23.25",
|
||||||
@@ -8943,13 +9134,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.9.0"
|
version = "0.9.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
|
checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand_chacha 0.9.0",
|
"rand_chacha 0.9.0",
|
||||||
"rand_core 0.9.1",
|
"rand_core 0.9.1",
|
||||||
"zerocopy 0.8.20",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -11016,7 +11206,7 @@ dependencies = [
|
|||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"postgres-protocol",
|
"postgres-protocol",
|
||||||
"postgres-types",
|
"postgres-types",
|
||||||
"rand 0.9.0",
|
"rand 0.9.1",
|
||||||
"socket2",
|
"socket2",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
|
|||||||
+10
-5
@@ -1,27 +1,32 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nym-outfox"
|
name = "nym-outfox"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
description = "Outfox package format"
|
description = "Outfox package format"
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
license = { workspace = true }
|
license = { workspace = true }
|
||||||
repository = { workspace = true }
|
repository = { workspace = true }
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rayon = { workspace = true }
|
rayon = { workspace = true }
|
||||||
blake3 = { workspace = true }
|
blake3 = { workspace = true }
|
||||||
zeroize = { workspace = true }
|
zeroize = { workspace = true }
|
||||||
chacha20 = { workspace = true, features = ["std"] }
|
chacha20 = { workspace = true, features = ["std"] }
|
||||||
x25519-dalek = { workspace = true }
|
|
||||||
chacha20poly1305 = { workspace = true }
|
chacha20poly1305 = { workspace = true }
|
||||||
getrandom = { workspace = true, features = ["js"] }
|
getrandom = { workspace = true, features = ["js"] }
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
sphinx-packet = { workspace = true }
|
|
||||||
rand = { workspace = true }
|
|
||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
|
|
||||||
|
rand = "0.9.1"
|
||||||
|
bs58 = "0.5.1"
|
||||||
|
libcrux-kem = "0.0.3"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
criterion = { workspace = true }
|
criterion = { workspace = true }
|
||||||
fastrand = { workspace = true }
|
fastrand = { workspace = true }
|
||||||
|
|
||||||
|
|
||||||
|
[[bench]]
|
||||||
|
name = "bench"
|
||||||
|
harness = false
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# Outfox
|
||||||
|
|
||||||
|
## Notes from Georgio:
|
||||||
|
|
||||||
|
### DO NOT INTEGRATE BEFORE:
|
||||||
|
- Checking the situation with empty Nonces/Additional Data for `ChaCha20Poly1305` calls marked by HAZARD.
|
||||||
|
- Programmatically checking which KEM is used during packet handling, and handling related errors.
|
||||||
|
- Crypto audit of `src/lion.rs`.
|
||||||
|
- Updating documentation to replace discrete-log operations with KEM operations.
|
||||||
|
|
||||||
|
### Things to optimize:
|
||||||
|
- Copying and allocations.
|
||||||
|
- Using libcrux for `ChaCha20`/`ChaCha20Poly1305`.
|
||||||
@@ -0,0 +1,285 @@
|
|||||||
|
use criterion::{criterion_group, criterion_main, Criterion};
|
||||||
|
use libcrux_kem::key_gen;
|
||||||
|
use nym_outfox::{
|
||||||
|
format::MixStageParameters,
|
||||||
|
packet::OutfoxPacket,
|
||||||
|
route::{Destination, DestinationAddressBytes, Node, NodeAddressBytes, NODE_ADDRESS_LENGTH},
|
||||||
|
};
|
||||||
|
use std::iter::repeat_with;
|
||||||
|
|
||||||
|
pub fn randombytes(n: usize) -> Vec<u8> {
|
||||||
|
repeat_with(|| fastrand::u8(..)).take(n).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_encode_decode(c: &mut Criterion) {
|
||||||
|
for kem in [
|
||||||
|
libcrux_kem::Algorithm::X25519,
|
||||||
|
libcrux_kem::Algorithm::XWingKemDraft06,
|
||||||
|
libcrux_kem::Algorithm::MlKem768,
|
||||||
|
] {
|
||||||
|
let mix_params = MixStageParameters {
|
||||||
|
kem: kem,
|
||||||
|
routing_information_length_bytes: 32,
|
||||||
|
remaining_header_length_bytes: (32 + 16 + 32) * 4,
|
||||||
|
payload_length_bytes: 1024, // 1kb
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut rng = rand::rng();
|
||||||
|
let (mix_decapsulation_key, mix_encapsulation_key) = key_gen(kem, &mut rng).unwrap();
|
||||||
|
|
||||||
|
let routing = [0; 32];
|
||||||
|
let destination = [0; 32];
|
||||||
|
|
||||||
|
let buffer = randombytes(mix_params.incoming_packet_length());
|
||||||
|
|
||||||
|
let mut new_buffer = buffer.clone();
|
||||||
|
|
||||||
|
let node_address_bytes = NodeAddressBytes::from_bytes(routing);
|
||||||
|
|
||||||
|
let node = Node::new(kem, node_address_bytes, mix_encapsulation_key);
|
||||||
|
|
||||||
|
let _ = mix_params
|
||||||
|
.encode_mix_layer(&mut rng, &mut new_buffer[..], &node.pub_key, &destination)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_ne!(
|
||||||
|
new_buffer[mix_params.payload_range()],
|
||||||
|
buffer[mix_params.payload_range()]
|
||||||
|
);
|
||||||
|
assert_ne!(new_buffer[mix_params.routing_data_range()], routing[..]);
|
||||||
|
|
||||||
|
let _ = mix_params
|
||||||
|
.decode_mix_layer(&mut new_buffer[..], &mix_decapsulation_key)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
new_buffer[mix_params.payload_range()],
|
||||||
|
buffer[mix_params.payload_range()]
|
||||||
|
);
|
||||||
|
assert_eq!(new_buffer[mix_params.routing_data_range()], routing[..]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn kem_str(kem: libcrux_kem::Algorithm) -> &'static str {
|
||||||
|
match kem {
|
||||||
|
libcrux_kem::Algorithm::X25519 => "KEM: x25519",
|
||||||
|
libcrux_kem::Algorithm::XWingKemDraft06 => "KEM: XWing",
|
||||||
|
libcrux_kem::Algorithm::MlKem768 => "KEM: MlKem768",
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_packet(c: &mut Criterion) {
|
||||||
|
let mut rng = rand::rng();
|
||||||
|
for kem in [
|
||||||
|
libcrux_kem::Algorithm::X25519,
|
||||||
|
libcrux_kem::Algorithm::XWingKemDraft06,
|
||||||
|
libcrux_kem::Algorithm::MlKem768,
|
||||||
|
] {
|
||||||
|
let (entry_sk, entry_pk) = key_gen(kem, &mut rng).unwrap();
|
||||||
|
let entry_node = Node::new(
|
||||||
|
kem,
|
||||||
|
NodeAddressBytes::from_bytes([5u8; NODE_ADDRESS_LENGTH]),
|
||||||
|
entry_pk,
|
||||||
|
);
|
||||||
|
let (node1_sk, node1_pk) = key_gen(kem, &mut rng).unwrap();
|
||||||
|
let node1 = Node::new(
|
||||||
|
kem,
|
||||||
|
NodeAddressBytes::from_bytes([0u8; NODE_ADDRESS_LENGTH]),
|
||||||
|
node1_pk,
|
||||||
|
);
|
||||||
|
let (node2_sk, node2_pk) = key_gen(kem, &mut rng).unwrap();
|
||||||
|
let node2 = Node::new(
|
||||||
|
kem,
|
||||||
|
NodeAddressBytes::from_bytes([1u8; NODE_ADDRESS_LENGTH]),
|
||||||
|
node2_pk,
|
||||||
|
);
|
||||||
|
let (node3_sk, node3_pk) = key_gen(kem, &mut rng).unwrap();
|
||||||
|
let node3 = Node::new(
|
||||||
|
kem,
|
||||||
|
NodeAddressBytes::from_bytes([2u8; NODE_ADDRESS_LENGTH]),
|
||||||
|
node3_pk,
|
||||||
|
);
|
||||||
|
|
||||||
|
let (exit_sk, exit_pk) = key_gen(kem, &mut rng).unwrap();
|
||||||
|
let exit = Node::new(
|
||||||
|
kem,
|
||||||
|
NodeAddressBytes::from_bytes([3u8; NODE_ADDRESS_LENGTH]),
|
||||||
|
exit_pk,
|
||||||
|
);
|
||||||
|
|
||||||
|
c.bench_function(&format!("{} | Key Generation", kem_str(kem)), |b| {
|
||||||
|
b.iter(|| key_gen(kem, &mut rng).unwrap())
|
||||||
|
});
|
||||||
|
|
||||||
|
let destination = Destination::new(
|
||||||
|
DestinationAddressBytes::from_bytes([9u8; NODE_ADDRESS_LENGTH]),
|
||||||
|
[0u8; 16],
|
||||||
|
);
|
||||||
|
|
||||||
|
let route = [
|
||||||
|
entry_node,
|
||||||
|
node1.clone(),
|
||||||
|
node2.clone(),
|
||||||
|
node3.clone(),
|
||||||
|
exit.clone(),
|
||||||
|
];
|
||||||
|
|
||||||
|
for payload_size in [512, 1000, 1024, 2048, 4096] {
|
||||||
|
c.bench_function(
|
||||||
|
&format!(
|
||||||
|
"{} | Packet Construction | Payload: {} bytes",
|
||||||
|
kem_str(kem),
|
||||||
|
payload_size
|
||||||
|
),
|
||||||
|
|b| {
|
||||||
|
b.iter_batched(
|
||||||
|
|| (rand::rng(), randombytes(payload_size)),
|
||||||
|
|(mut rng, payload)| {
|
||||||
|
OutfoxPacket::build(
|
||||||
|
&mut rng,
|
||||||
|
kem,
|
||||||
|
&payload,
|
||||||
|
&route,
|
||||||
|
&destination,
|
||||||
|
Some(payload.len()),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
criterion::BatchSize::PerIteration,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
let payload = randombytes(payload_size);
|
||||||
|
|
||||||
|
let packet = OutfoxPacket::build(
|
||||||
|
&mut rng,
|
||||||
|
kem,
|
||||||
|
&payload,
|
||||||
|
&route,
|
||||||
|
&destination,
|
||||||
|
Some(payload.len()),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let packet_bytes = packet.to_bytes().unwrap();
|
||||||
|
|
||||||
|
let mut packet = OutfoxPacket::try_from((kem, packet_bytes.as_slice())).unwrap();
|
||||||
|
|
||||||
|
c.bench_function(
|
||||||
|
&format!(
|
||||||
|
"{} | Packet Decoding (Entry) | Payload: {} bytes",
|
||||||
|
kem_str(kem),
|
||||||
|
payload_size
|
||||||
|
),
|
||||||
|
|b| {
|
||||||
|
b.iter_batched(
|
||||||
|
|| OutfoxPacket::try_from((kem, packet_bytes.as_slice())).unwrap(),
|
||||||
|
|mut packet| packet.decode_next_layer(&entry_sk).unwrap(),
|
||||||
|
criterion::BatchSize::PerIteration,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
c.bench_function(
|
||||||
|
&format!(
|
||||||
|
"{} | Packet Decoding (Layer 1) | Payload: {} bytes",
|
||||||
|
kem_str(kem),
|
||||||
|
payload_size
|
||||||
|
),
|
||||||
|
|b| {
|
||||||
|
b.iter_batched(
|
||||||
|
|| {
|
||||||
|
let mut packet =
|
||||||
|
OutfoxPacket::try_from((kem, packet_bytes.as_slice())).unwrap();
|
||||||
|
packet.decode_next_layer(&entry_sk).unwrap();
|
||||||
|
packet
|
||||||
|
},
|
||||||
|
|mut packet| packet.decode_next_layer(&node1_sk).unwrap(),
|
||||||
|
criterion::BatchSize::PerIteration,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
c.bench_function(
|
||||||
|
&format!(
|
||||||
|
"{} | Packet Decoding (Layer 2) | Payload: {} bytes",
|
||||||
|
kem_str(kem),
|
||||||
|
payload_size
|
||||||
|
),
|
||||||
|
|b| {
|
||||||
|
b.iter_batched(
|
||||||
|
|| {
|
||||||
|
let mut packet =
|
||||||
|
OutfoxPacket::try_from((kem, packet_bytes.as_slice())).unwrap();
|
||||||
|
packet.decode_next_layer(&entry_sk).unwrap();
|
||||||
|
packet.decode_next_layer(&node1_sk).unwrap();
|
||||||
|
packet
|
||||||
|
},
|
||||||
|
|mut packet| packet.decode_next_layer(&node2_sk).unwrap(),
|
||||||
|
criterion::BatchSize::PerIteration,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
c.bench_function(
|
||||||
|
&format!(
|
||||||
|
"{} | Packet Decoding (Layer 3) | Payload: {} bytes",
|
||||||
|
kem_str(kem),
|
||||||
|
payload_size
|
||||||
|
),
|
||||||
|
|b| {
|
||||||
|
b.iter_batched(
|
||||||
|
|| {
|
||||||
|
let mut packet =
|
||||||
|
OutfoxPacket::try_from((kem, packet_bytes.as_slice())).unwrap();
|
||||||
|
packet.decode_next_layer(&entry_sk).unwrap();
|
||||||
|
packet.decode_next_layer(&node1_sk).unwrap();
|
||||||
|
packet.decode_next_layer(&node2_sk).unwrap();
|
||||||
|
packet
|
||||||
|
},
|
||||||
|
|mut packet| packet.decode_next_layer(&node3_sk).unwrap(),
|
||||||
|
criterion::BatchSize::PerIteration,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
c.bench_function(
|
||||||
|
&format!(
|
||||||
|
"{} | Packet Decoding + Plaintext Recovery (exit) | Payload: {} bytes",
|
||||||
|
kem_str(kem),
|
||||||
|
payload_size
|
||||||
|
),
|
||||||
|
|b| {
|
||||||
|
b.iter_batched(
|
||||||
|
|| {
|
||||||
|
let mut packet =
|
||||||
|
OutfoxPacket::try_from((kem, packet_bytes.as_slice())).unwrap();
|
||||||
|
packet.decode_next_layer(&entry_sk).unwrap();
|
||||||
|
packet.decode_next_layer(&node1_sk).unwrap();
|
||||||
|
packet.decode_next_layer(&node2_sk).unwrap();
|
||||||
|
packet.decode_next_layer(&node3_sk).unwrap();
|
||||||
|
packet
|
||||||
|
},
|
||||||
|
|mut packet| {
|
||||||
|
packet.decode_next_layer(&exit_sk).unwrap();
|
||||||
|
packet.recover_plaintext()
|
||||||
|
},
|
||||||
|
criterion::BatchSize::PerIteration,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
let next_address = packet.decode_next_layer(&entry_sk).unwrap();
|
||||||
|
assert_eq!(&next_address, node1.address.as_bytes());
|
||||||
|
let next_address = packet.decode_next_layer(&node1_sk).unwrap();
|
||||||
|
assert_eq!(&next_address, node2.address.as_bytes());
|
||||||
|
let next_address = packet.decode_next_layer(&node2_sk).unwrap();
|
||||||
|
assert_eq!(&next_address, node3.address.as_bytes());
|
||||||
|
let next_address = packet.decode_next_layer(&node3_sk).unwrap();
|
||||||
|
assert_eq!(&next_address, exit.address.as_bytes());
|
||||||
|
let destination_address = packet.decode_next_layer(&exit_sk).unwrap();
|
||||||
|
assert_eq!(destination_address, destination.address.as_bytes());
|
||||||
|
|
||||||
|
assert_eq!(payload, packet.recover_plaintext().unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
criterion_group!(benches, test_packet);
|
||||||
|
criterion_main!(benches);
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use libcrux_kem::Algorithm;
|
||||||
|
|
||||||
pub const GROUPELEMENTBYTES: u8 = 32;
|
pub const GROUPELEMENTBYTES: u8 = 32;
|
||||||
pub const TAGBYTES: u8 = 16;
|
pub const TAGBYTES: u8 = 16;
|
||||||
pub const MIX_PARAMS_LEN: usize = DEFAULT_HOPS + 2;
|
pub const MIX_PARAMS_LEN: usize = DEFAULT_HOPS + 2;
|
||||||
@@ -5,18 +7,25 @@ pub const MIN_MESSAGE_LEN: usize = 24 * 2;
|
|||||||
pub(crate) const CONTEXT: &str = "LIONKEYS";
|
pub(crate) const CONTEXT: &str = "LIONKEYS";
|
||||||
pub(crate) const TAG_LEN: usize = 24;
|
pub(crate) const TAG_LEN: usize = 24;
|
||||||
pub const DEFAULT_ROUTING_INFO_SIZE: u8 = 32;
|
pub const DEFAULT_ROUTING_INFO_SIZE: u8 = 32;
|
||||||
pub const DEFAULT_HOPS: usize = 4;
|
pub const DEFAULT_HOPS: usize = 5;
|
||||||
pub const ROUTING_INFORMATION_LENGTH_BY_STAGE: [u8; DEFAULT_HOPS] =
|
pub const ROUTING_INFORMATION_LENGTH_BY_STAGE: [u8; DEFAULT_HOPS] =
|
||||||
[DEFAULT_ROUTING_INFO_SIZE; DEFAULT_HOPS];
|
[DEFAULT_ROUTING_INFO_SIZE; DEFAULT_HOPS];
|
||||||
pub const MIN_PACKET_SIZE: usize = 48;
|
pub const MIN_PACKET_SIZE: usize = 48;
|
||||||
pub const MAGIC_SLICE: &[u8] = &[111, 102, 120];
|
pub const MAGIC_SLICE: &[u8] = &[111, 102, 120];
|
||||||
|
|
||||||
pub const OUTFOX_PACKET_OVERHEAD: usize = MIX_PARAMS_LEN
|
pub const fn outfox_packet_overhead(kem: Algorithm) -> usize {
|
||||||
+ (groupelementbytes() + tagbytes() + DEFAULT_ROUTING_INFO_SIZE as usize) * DEFAULT_HOPS
|
MIX_PARAMS_LEN
|
||||||
+ MAGIC_SLICE.len();
|
+ (groupelementbytes(kem) + tagbytes() + DEFAULT_ROUTING_INFO_SIZE as usize) * DEFAULT_HOPS
|
||||||
|
+ MAGIC_SLICE.len()
|
||||||
|
}
|
||||||
|
|
||||||
pub const fn groupelementbytes() -> usize {
|
pub const fn groupelementbytes(kem: Algorithm) -> usize {
|
||||||
GROUPELEMENTBYTES as usize
|
match kem {
|
||||||
|
Algorithm::XWingKemDraft06 => 1120,
|
||||||
|
Algorithm::X25519 => 32,
|
||||||
|
Algorithm::MlKem768 => 1088,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn tagbytes() -> usize {
|
pub const fn tagbytes() -> usize {
|
||||||
|
|||||||
@@ -28,4 +28,7 @@ pub enum OutfoxError {
|
|||||||
InvalidHeaderLength(usize),
|
InvalidHeaderLength(usize),
|
||||||
#[error("Invalid magic bytes, expected: {:?}, got: {:?}", MAGIC_SLICE, 0)]
|
#[error("Invalid magic bytes, expected: {:?}, got: {:?}", MAGIC_SLICE, 0)]
|
||||||
InvalidMagicBytes(Vec<u8>),
|
InvalidMagicBytes(Vec<u8>),
|
||||||
|
|
||||||
|
#[error("routing information processing failure {0}")]
|
||||||
|
InvalidRouting(String),
|
||||||
}
|
}
|
||||||
|
|||||||
+77
-44
@@ -58,22 +58,30 @@ use crate::constants::groupelementbytes;
|
|||||||
use crate::constants::tagbytes;
|
use crate::constants::tagbytes;
|
||||||
use crate::constants::DEFAULT_HOPS;
|
use crate::constants::DEFAULT_HOPS;
|
||||||
use crate::constants::DEFAULT_ROUTING_INFO_SIZE;
|
use crate::constants::DEFAULT_ROUTING_INFO_SIZE;
|
||||||
use crate::constants::GROUPELEMENTBYTES;
|
|
||||||
use crate::constants::MIX_PARAMS_LEN;
|
use crate::constants::MIX_PARAMS_LEN;
|
||||||
use crate::constants::ROUTING_INFORMATION_LENGTH_BY_STAGE;
|
use crate::constants::ROUTING_INFORMATION_LENGTH_BY_STAGE;
|
||||||
use crate::constants::TAGBYTES;
|
use crate::constants::TAGBYTES;
|
||||||
use crate::error::OutfoxError;
|
use crate::error::OutfoxError;
|
||||||
use crate::lion::*;
|
use crate::lion::*;
|
||||||
|
|
||||||
|
use rand::CryptoRng;
|
||||||
|
|
||||||
use chacha20poly1305::AeadInPlace;
|
use chacha20poly1305::AeadInPlace;
|
||||||
use chacha20poly1305::ChaCha20Poly1305;
|
use chacha20poly1305::ChaCha20Poly1305;
|
||||||
use chacha20poly1305::KeyInit;
|
use chacha20poly1305::KeyInit;
|
||||||
use chacha20poly1305::Tag;
|
use chacha20poly1305::Tag;
|
||||||
|
use libcrux_kem::Algorithm;
|
||||||
|
use libcrux_kem::Ct;
|
||||||
|
use libcrux_kem::PrivateKey;
|
||||||
|
use libcrux_kem::PublicKey;
|
||||||
|
use libcrux_kem::Ss;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
/// A structure that holds mix packet construction parameters. These incluse the length
|
/// A structure that holds mix packet construction parameters. These incluse the length
|
||||||
/// of the routing information at each hop, the number of hops, and the payload length.
|
/// of the routing information at each hop, the number of hops, and the payload length.
|
||||||
#[derive(Eq, PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
pub struct MixCreationParameters {
|
pub struct MixCreationParameters {
|
||||||
|
pub kem: Algorithm,
|
||||||
/// The routing length is inner first, so \[0\] is the innermost routing length, etc (in bytes)
|
/// The routing length is inner first, so \[0\] is the innermost routing length, etc (in bytes)
|
||||||
/// In our stratified topology this will always be 4
|
/// In our stratified topology this will always be 4
|
||||||
pub routing_information_length_by_stage: [u8; DEFAULT_HOPS],
|
pub routing_information_length_by_stage: [u8; DEFAULT_HOPS],
|
||||||
@@ -81,15 +89,16 @@ pub struct MixCreationParameters {
|
|||||||
pub payload_length_bytes: u16,
|
pub payload_length_bytes: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&[u8]> for MixCreationParameters {
|
impl TryFrom<(Algorithm, &[u8])> for MixCreationParameters {
|
||||||
type Error = OutfoxError;
|
type Error = OutfoxError;
|
||||||
|
|
||||||
fn try_from(v: &[u8]) -> Result<Self, Self::Error> {
|
fn try_from(v: (Algorithm, &[u8])) -> Result<Self, Self::Error> {
|
||||||
if v.len() != MIX_PARAMS_LEN {
|
if v.1.len() != MIX_PARAMS_LEN {
|
||||||
return Err(OutfoxError::InvalidHeaderLength(v.len()));
|
return Err(OutfoxError::InvalidHeaderLength(v.1.len()));
|
||||||
}
|
}
|
||||||
let (routing, payload) = v.split_at(DEFAULT_HOPS);
|
let (routing, payload) = v.1.split_at(DEFAULT_HOPS);
|
||||||
Ok(MixCreationParameters {
|
Ok(MixCreationParameters {
|
||||||
|
kem: v.0,
|
||||||
routing_information_length_by_stage: routing.try_into()?,
|
routing_information_length_by_stage: routing.try_into()?,
|
||||||
payload_length_bytes: u16::from_le_bytes(payload.try_into()?),
|
payload_length_bytes: u16::from_le_bytes(payload.try_into()?),
|
||||||
})
|
})
|
||||||
@@ -98,7 +107,7 @@ impl TryFrom<&[u8]> for MixCreationParameters {
|
|||||||
|
|
||||||
impl MixCreationParameters {
|
impl MixCreationParameters {
|
||||||
pub fn to_bytes(&self) -> Vec<u8> {
|
pub fn to_bytes(&self) -> Vec<u8> {
|
||||||
let mut bytes = Vec::with_capacity(5);
|
let mut bytes = Vec::with_capacity(DEFAULT_HOPS + 1);
|
||||||
bytes.extend_from_slice(self.routing_information_length_by_stage.as_slice());
|
bytes.extend_from_slice(self.routing_information_length_by_stage.as_slice());
|
||||||
bytes.extend_from_slice(&self.payload_length_bytes.to_le_bytes());
|
bytes.extend_from_slice(&self.payload_length_bytes.to_le_bytes());
|
||||||
bytes
|
bytes
|
||||||
@@ -109,8 +118,9 @@ impl MixCreationParameters {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a set of parameters for a mix packet format.
|
/// Create a set of parameters for a mix packet format.
|
||||||
pub fn new(payload_length_bytes: u16) -> MixCreationParameters {
|
pub fn new(kem: Algorithm, payload_length_bytes: u16) -> MixCreationParameters {
|
||||||
MixCreationParameters {
|
MixCreationParameters {
|
||||||
|
kem: kem,
|
||||||
routing_information_length_by_stage: [DEFAULT_ROUTING_INFO_SIZE; DEFAULT_HOPS],
|
routing_information_length_by_stage: [DEFAULT_ROUTING_INFO_SIZE; DEFAULT_HOPS],
|
||||||
payload_length_bytes,
|
payload_length_bytes,
|
||||||
}
|
}
|
||||||
@@ -120,7 +130,7 @@ impl MixCreationParameters {
|
|||||||
pub fn total_packet_length(&self) -> usize {
|
pub fn total_packet_length(&self) -> usize {
|
||||||
let mut len = self.payload_length_bytes();
|
let mut len = self.payload_length_bytes();
|
||||||
for stage_len in ROUTING_INFORMATION_LENGTH_BY_STAGE.iter() {
|
for stage_len in ROUTING_INFORMATION_LENGTH_BY_STAGE.iter() {
|
||||||
len += *stage_len as usize + groupelementbytes() + tagbytes()
|
len += *stage_len as usize + groupelementbytes(self.kem) + tagbytes()
|
||||||
}
|
}
|
||||||
len
|
len
|
||||||
}
|
}
|
||||||
@@ -133,6 +143,7 @@ impl MixCreationParameters {
|
|||||||
for (i, stage_len) in ROUTING_INFORMATION_LENGTH_BY_STAGE.iter().enumerate() {
|
for (i, stage_len) in ROUTING_INFORMATION_LENGTH_BY_STAGE.iter().enumerate() {
|
||||||
if i == layer_number {
|
if i == layer_number {
|
||||||
let params = MixStageParameters {
|
let params = MixStageParameters {
|
||||||
|
kem: self.kem,
|
||||||
routing_information_length_bytes: *stage_len,
|
routing_information_length_bytes: *stage_len,
|
||||||
remaining_header_length_bytes,
|
remaining_header_length_bytes,
|
||||||
payload_length_bytes: self.payload_length_bytes,
|
payload_length_bytes: self.payload_length_bytes,
|
||||||
@@ -143,7 +154,8 @@ impl MixCreationParameters {
|
|||||||
|
|
||||||
return (total_size - inner_size..total_size, params);
|
return (total_size - inner_size..total_size, params);
|
||||||
} else {
|
} else {
|
||||||
remaining_header_length_bytes += (stage_len + GROUPELEMENTBYTES + TAGBYTES) as u16;
|
remaining_header_length_bytes +=
|
||||||
|
groupelementbytes(self.kem) as u16 + (stage_len + TAGBYTES) as u16;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,6 +165,7 @@ impl MixCreationParameters {
|
|||||||
|
|
||||||
/// A structure representing the parameters of a single stage of mixing.
|
/// A structure representing the parameters of a single stage of mixing.
|
||||||
pub struct MixStageParameters {
|
pub struct MixStageParameters {
|
||||||
|
pub kem: Algorithm,
|
||||||
/// The routing information length for this stage of mixing
|
/// The routing information length for this stage of mixing
|
||||||
pub routing_information_length_bytes: u8,
|
pub routing_information_length_bytes: u8,
|
||||||
/// The reamining header length for this stage of mixing
|
/// The reamining header length for this stage of mixing
|
||||||
@@ -175,7 +188,7 @@ impl MixStageParameters {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn incoming_packet_length(&self) -> usize {
|
pub fn incoming_packet_length(&self) -> usize {
|
||||||
groupelementbytes() + tagbytes() + self.outgoing_packet_length()
|
groupelementbytes(self.kem) + tagbytes() + self.outgoing_packet_length()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn outgoing_packet_length(&self) -> usize {
|
pub fn outgoing_packet_length(&self) -> usize {
|
||||||
@@ -184,22 +197,22 @@ impl MixStageParameters {
|
|||||||
+ self.payload_length_bytes()
|
+ self.payload_length_bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pub_element_range(&self) -> Range<usize> {
|
pub fn encaps_element_range(&self) -> Range<usize> {
|
||||||
0..groupelementbytes()
|
0..groupelementbytes(self.kem)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tag_range(&self) -> Range<usize> {
|
pub fn tag_range(&self) -> Range<usize> {
|
||||||
groupelementbytes()..groupelementbytes() + tagbytes()
|
groupelementbytes(self.kem)..groupelementbytes(self.kem) + tagbytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn routing_data_range(&self) -> Range<usize> {
|
pub fn routing_data_range(&self) -> Range<usize> {
|
||||||
groupelementbytes() + tagbytes()
|
groupelementbytes(self.kem) + tagbytes()
|
||||||
..groupelementbytes() + tagbytes() + self.routing_information_length_bytes()
|
..groupelementbytes(self.kem) + tagbytes() + self.routing_information_length_bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn header_range(&self) -> Range<usize> {
|
pub fn header_range(&self) -> Range<usize> {
|
||||||
groupelementbytes() + tagbytes()
|
groupelementbytes(self.kem) + tagbytes()
|
||||||
..groupelementbytes()
|
..groupelementbytes(self.kem)
|
||||||
+ tagbytes()
|
+ tagbytes()
|
||||||
+ self.routing_information_length_bytes()
|
+ self.routing_information_length_bytes()
|
||||||
+ self.remaining_header_length_bytes()
|
+ self.remaining_header_length_bytes()
|
||||||
@@ -209,13 +222,16 @@ impl MixStageParameters {
|
|||||||
self.incoming_packet_length() - self.payload_length_bytes()..self.incoming_packet_length()
|
self.incoming_packet_length() - self.payload_length_bytes()..self.incoming_packet_length()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn encode_mix_layer(
|
pub fn encode_mix_layer<R>(
|
||||||
&self,
|
&self,
|
||||||
|
rng: &mut R,
|
||||||
buffer: &mut [u8],
|
buffer: &mut [u8],
|
||||||
user_secret_key: &x25519_dalek::StaticSecret,
|
mix_encapsulation_key: &PublicKey,
|
||||||
mix_public_key: x25519_dalek::PublicKey,
|
|
||||||
destination: &[u8; 32],
|
destination: &[u8; 32],
|
||||||
) -> Result<x25519_dalek::SharedSecret, OutfoxError> {
|
) -> Result<Ss, OutfoxError>
|
||||||
|
where
|
||||||
|
R: CryptoRng,
|
||||||
|
{
|
||||||
let routing_data = destination;
|
let routing_data = destination;
|
||||||
|
|
||||||
if buffer.len() != self.incoming_packet_length() {
|
if buffer.len() != self.incoming_packet_length() {
|
||||||
@@ -232,14 +248,18 @@ impl MixStageParameters {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let user_public_key = x25519_dalek::PublicKey::from(user_secret_key);
|
let (ss, ct) = mix_encapsulation_key.encapsulate(rng).unwrap();
|
||||||
let shared_key = user_secret_key.diffie_hellman(&mix_public_key);
|
|
||||||
|
let shared_key = ss.encode();
|
||||||
|
|
||||||
// Copy rounting data into buffer
|
// Copy rounting data into buffer
|
||||||
buffer[self.routing_data_range()].copy_from_slice(routing_data);
|
buffer[self.routing_data_range()].copy_from_slice(routing_data);
|
||||||
|
|
||||||
// Perform the AEAD
|
// Perform the AEAD
|
||||||
let header_aead_key = ChaCha20Poly1305::new_from_slice(shared_key.as_bytes())?;
|
|
||||||
|
// HAZARD: ENCRYPTION WITH EMPTY NONCES AND NO AD!!
|
||||||
|
|
||||||
|
let header_aead_key = ChaCha20Poly1305::new_from_slice(&shared_key)?;
|
||||||
let nonce = [0u8; 12];
|
let nonce = [0u8; 12];
|
||||||
|
|
||||||
let tag = header_aead_key
|
let tag = header_aead_key
|
||||||
@@ -250,18 +270,18 @@ impl MixStageParameters {
|
|||||||
buffer[self.tag_range()].copy_from_slice(&tag[..]);
|
buffer[self.tag_range()].copy_from_slice(&tag[..]);
|
||||||
|
|
||||||
// Copy own public key into buffer
|
// Copy own public key into buffer
|
||||||
buffer[self.pub_element_range()].copy_from_slice(user_public_key.as_bytes());
|
buffer[self.encaps_element_range()].copy_from_slice(&ct.encode());
|
||||||
|
|
||||||
// Do a round of LION on the payload
|
// Do a round of LION on the payload
|
||||||
lion_transform_encrypt(&mut buffer[self.payload_range()], shared_key.as_bytes())?;
|
lion_transform_encrypt(&mut buffer[self.payload_range()], &shared_key)?;
|
||||||
|
|
||||||
Ok(shared_key)
|
Ok(ss)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decode_mix_layer(
|
pub fn decode_mix_layer(
|
||||||
&self,
|
&self,
|
||||||
buffer: &mut [u8],
|
buffer: &mut [u8],
|
||||||
mix_secret_key: &x25519_dalek::StaticSecret,
|
mix_decapsulation_key: &PrivateKey,
|
||||||
) -> Result<Vec<u8>, OutfoxError> {
|
) -> Result<Vec<u8>, OutfoxError> {
|
||||||
// Check the length of the incoming buffer is correct.
|
// Check the length of the incoming buffer is correct.
|
||||||
if buffer.len() != self.incoming_packet_length() {
|
if buffer.len() != self.incoming_packet_length() {
|
||||||
@@ -271,13 +291,14 @@ impl MixStageParameters {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Derive the shared key for this packet
|
let ct = Ct::decode(self.kem, &buffer[self.encaps_element_range()]).unwrap();
|
||||||
let user_public_key_bytes: [u8; 32] = buffer[self.pub_element_range()].try_into()?;
|
let shared_key = ct.decapsulate(&mix_decapsulation_key).unwrap();
|
||||||
let user_public_key = x25519_dalek::PublicKey::from(user_public_key_bytes);
|
let shared_key = shared_key.encode();
|
||||||
let shared_key = mix_secret_key.diffie_hellman(&user_public_key);
|
|
||||||
|
|
||||||
// Compute the AEAD and check the Tag, if wrong return Err
|
// Compute the AEAD and check the Tag, if wrong return Err
|
||||||
let header_aead_key = ChaCha20Poly1305::new_from_slice(shared_key.as_bytes())?;
|
let header_aead_key = ChaCha20Poly1305::new_from_slice(&shared_key)?;
|
||||||
|
|
||||||
|
// HAZARD: ENCRYPTION WITH EMPTY NONCES AND NO AD!!
|
||||||
let nonce = [0; 12];
|
let nonce = [0; 12];
|
||||||
|
|
||||||
let tag_bytes = buffer[self.tag_range()].to_vec();
|
let tag_bytes = buffer[self.tag_range()].to_vec();
|
||||||
@@ -294,7 +315,7 @@ impl MixStageParameters {
|
|||||||
|
|
||||||
let routing_data = buffer[self.routing_data_range()].to_vec();
|
let routing_data = buffer[self.routing_data_range()].to_vec();
|
||||||
// Do a round of LION on the payload
|
// Do a round of LION on the payload
|
||||||
lion_transform_decrypt(&mut buffer[self.payload_range()], shared_key.as_bytes())?;
|
lion_transform_decrypt(&mut buffer[self.payload_range()], &shared_key)?;
|
||||||
|
|
||||||
Ok(routing_data)
|
Ok(routing_data)
|
||||||
}
|
}
|
||||||
@@ -306,17 +327,29 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_to_bytes() {
|
fn test_to_bytes() {
|
||||||
let mix_params = MixCreationParameters::new(1024);
|
for kem in [
|
||||||
assert_eq!(mix_params.to_bytes(), vec![32, 32, 32, 32, 0, 4])
|
libcrux_kem::Algorithm::X25519,
|
||||||
|
libcrux_kem::Algorithm::XWingKemDraft06,
|
||||||
|
libcrux_kem::Algorithm::MlKem768,
|
||||||
|
] {
|
||||||
|
let mix_params = MixCreationParameters::new(kem, 1024);
|
||||||
|
assert_eq!(mix_params.to_bytes(), vec![32, 32, 32, 32, 32, 0, 4]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_from_bytes() {
|
fn test_from_bytes() {
|
||||||
let params_bytes = vec![32, 32, 32, 32, 0, 4];
|
let params_bytes = vec![32, 32, 32, 32, 32, 0, 4];
|
||||||
let mix_params = MixCreationParameters::new(1024);
|
for kem in [
|
||||||
assert_eq!(
|
libcrux_kem::Algorithm::X25519,
|
||||||
mix_params,
|
libcrux_kem::Algorithm::XWingKemDraft06,
|
||||||
MixCreationParameters::try_from(params_bytes.as_slice()).unwrap()
|
libcrux_kem::Algorithm::MlKem768,
|
||||||
)
|
] {
|
||||||
|
let mix_params = MixCreationParameters::new(kem, 1024);
|
||||||
|
assert_eq!(
|
||||||
|
mix_params,
|
||||||
|
MixCreationParameters::try_from((kem, params_bytes.as_slice())).unwrap()
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,3 +3,34 @@ pub mod error;
|
|||||||
pub mod format;
|
pub mod format;
|
||||||
pub mod lion;
|
pub mod lion;
|
||||||
pub mod packet;
|
pub mod packet;
|
||||||
|
pub mod route;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use libcrux_kem::*;
|
||||||
|
use rand::rngs::OsRng;
|
||||||
|
use rand::TryRngCore;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_kem() {
|
||||||
|
let mut os_rng = OsRng;
|
||||||
|
let mut rng = os_rng.unwrap_mut();
|
||||||
|
|
||||||
|
let (sk_a, pk_a) = key_gen(Algorithm::MlKem768, &mut rng).unwrap();
|
||||||
|
|
||||||
|
let received_sk = sk_a.encode();
|
||||||
|
let received_pk = pk_a.encode();
|
||||||
|
|
||||||
|
let pk = PublicKey::decode(Algorithm::MlKem768, &received_pk).unwrap();
|
||||||
|
let (ss_b, ct_b) = pk.encapsulate(&mut rng).unwrap();
|
||||||
|
let received_ct = ct_b.encode();
|
||||||
|
|
||||||
|
println!("pk: {}", received_pk.len());
|
||||||
|
println!("sk: {}", received_sk.len());
|
||||||
|
println!("kem encaps: {}", received_ct.len());
|
||||||
|
|
||||||
|
let ct_a = Ct::decode(Algorithm::MlKem768, &received_ct).unwrap();
|
||||||
|
let ss_a = ct_a.decapsulate(&sk_a).unwrap();
|
||||||
|
assert_eq!(ss_b.encode(), ss_a.encode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+35
-26
@@ -1,29 +1,32 @@
|
|||||||
|
use libcrux_kem::{Algorithm, PrivateKey};
|
||||||
|
use rand::CryptoRng;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
constants::{DEFAULT_HOPS, MAGIC_SLICE, MIN_PACKET_SIZE, MIX_PARAMS_LEN},
|
constants::{DEFAULT_HOPS, MAGIC_SLICE, MIN_PACKET_SIZE, MIX_PARAMS_LEN},
|
||||||
error::OutfoxError,
|
error::OutfoxError,
|
||||||
format::{MixCreationParameters, MixStageParameters},
|
format::{MixCreationParameters, MixStageParameters},
|
||||||
|
route::{Destination, Node, DEFAULT_PAYLOAD_SIZE},
|
||||||
};
|
};
|
||||||
use sphinx_packet::{
|
|
||||||
crypto::PrivateKey,
|
|
||||||
packet::builder::DEFAULT_PAYLOAD_SIZE,
|
|
||||||
route::{Destination, Node},
|
|
||||||
};
|
|
||||||
use std::{array::TryFromSliceError, collections::VecDeque, ops::Range};
|
use std::{array::TryFromSliceError, collections::VecDeque, ops::Range};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct OutfoxPacket {
|
pub struct OutfoxPacket {
|
||||||
|
kem: Algorithm,
|
||||||
mix_params: MixCreationParameters,
|
mix_params: MixCreationParameters,
|
||||||
payload: Vec<u8>,
|
payload: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct OutfoxProcessedPacket {
|
pub struct OutfoxProcessedPacket {
|
||||||
|
kem: Algorithm,
|
||||||
packet: OutfoxPacket,
|
packet: OutfoxPacket,
|
||||||
next_address: [u8; 32],
|
next_address: [u8; 32],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OutfoxProcessedPacket {
|
impl OutfoxProcessedPacket {
|
||||||
pub fn new(packet: OutfoxPacket, next_address: [u8; 32]) -> Self {
|
pub fn new(kem: Algorithm, packet: OutfoxPacket, next_address: [u8; 32]) -> Self {
|
||||||
OutfoxProcessedPacket {
|
OutfoxProcessedPacket {
|
||||||
|
kem,
|
||||||
packet,
|
packet,
|
||||||
next_address,
|
next_address,
|
||||||
}
|
}
|
||||||
@@ -38,13 +41,14 @@ impl OutfoxProcessedPacket {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&[u8]> for OutfoxPacket {
|
impl TryFrom<(Algorithm, &[u8])> for OutfoxPacket {
|
||||||
type Error = OutfoxError;
|
type Error = OutfoxError;
|
||||||
|
|
||||||
fn try_from(v: &[u8]) -> Result<Self, Self::Error> {
|
fn try_from(v: (Algorithm, &[u8])) -> Result<Self, Self::Error> {
|
||||||
let (header, payload) = v.split_at(MIX_PARAMS_LEN);
|
let (header, payload) = v.1.split_at(MIX_PARAMS_LEN);
|
||||||
Ok(OutfoxPacket {
|
Ok(OutfoxPacket {
|
||||||
mix_params: MixCreationParameters::try_from(header)?,
|
kem: v.0,
|
||||||
|
mix_params: MixCreationParameters::try_from((v.0, header))?,
|
||||||
payload: payload.to_vec(),
|
payload: payload.to_vec(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -81,20 +85,24 @@ impl OutfoxPacket {
|
|||||||
Ok(bytes)
|
Ok(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build<M: AsRef<[u8]>>(
|
pub fn build<R, M: AsRef<[u8]>>(
|
||||||
|
rng: &mut R,
|
||||||
|
kem: Algorithm,
|
||||||
payload: M,
|
payload: M,
|
||||||
route: &[Node; 4],
|
route: &[Node; DEFAULT_HOPS],
|
||||||
destination: &Destination,
|
destination: &Destination,
|
||||||
packet_size: Option<usize>,
|
packet_size: Option<usize>,
|
||||||
) -> Result<OutfoxPacket, OutfoxError> {
|
) -> Result<OutfoxPacket, OutfoxError>
|
||||||
let secret_key = x25519_dalek::StaticSecret::random();
|
where
|
||||||
|
R: CryptoRng,
|
||||||
|
{
|
||||||
let packet_size = packet_size.unwrap_or(DEFAULT_PAYLOAD_SIZE);
|
let packet_size = packet_size.unwrap_or(DEFAULT_PAYLOAD_SIZE);
|
||||||
let packet_size = if packet_size < MIN_PACKET_SIZE {
|
let packet_size = if packet_size < MIN_PACKET_SIZE {
|
||||||
MIN_PACKET_SIZE
|
MIN_PACKET_SIZE
|
||||||
} else {
|
} else {
|
||||||
packet_size
|
packet_size
|
||||||
} + MAGIC_SLICE.len();
|
} + MAGIC_SLICE.len();
|
||||||
let mix_params = MixCreationParameters::new(packet_size as u16);
|
let mix_params = MixCreationParameters::new(kem, packet_size as u16);
|
||||||
|
|
||||||
let padding = mix_params.total_packet_length() - payload.as_ref().len() - MAGIC_SLICE.len();
|
let padding = mix_params.total_packet_length() - payload.as_ref().len() - MAGIC_SLICE.len();
|
||||||
let mut buffer = vec![0; padding];
|
let mut buffer = vec![0; padding];
|
||||||
@@ -104,38 +112,39 @@ impl OutfoxPacket {
|
|||||||
// Last node in the route is a gateway, it will decrypt last, and get the final destination address
|
// Last node in the route is a gateway, it will decrypt last, and get the final destination address
|
||||||
let (range, stage_params) = mix_params.get_stage_params(0);
|
let (range, stage_params) = mix_params.get_stage_params(0);
|
||||||
stage_params.encode_mix_layer(
|
stage_params.encode_mix_layer(
|
||||||
|
rng,
|
||||||
&mut buffer[range],
|
&mut buffer[range],
|
||||||
&secret_key,
|
&route.last().unwrap().pub_key,
|
||||||
route.last().unwrap().pub_key,
|
|
||||||
destination.address.as_bytes_ref(),
|
destination.address.as_bytes_ref(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let route = route.iter().rev().collect::<Vec<&Node>>();
|
let route = route.iter().rev().collect::<Vec<&Node>>();
|
||||||
|
|
||||||
// We've reversed the route, and we iterate pairs of node, first node in the pair is the destination, and the second(last) is the processing node
|
// We've reversed the route, and we iterate pairs of node, first node in the pair is the destination, and the second(last) is the processing node
|
||||||
// Route: [N1, N2, N3, G]
|
// Route: [Entry, N1, N2, N3, Exit]
|
||||||
// Reverse: [G, N3, N2, N1]
|
// Reverse: [Exit, N3, N2, N1, Entry]
|
||||||
// Pairs: [(G, N3), (N3, N2), (N2, N1)]
|
// Pairs: [(Exit, N3), (N3, N2), (N2, N1), (N1, Entry)]
|
||||||
// We iterate over pairs, and encode the mix layer for each pair
|
// We iterate over pairs, and encode the mix layer for each pair
|
||||||
// For the first pair, we encode the mix layer for N3, and the destination is G
|
// For the first pair, we encode the mix layer for N3, and the destination is Exit
|
||||||
// For the second pair, we encode the mix layer for N2, and the destination is N3
|
// For the second pair, we encode the mix layer for N2, and the destination is N3
|
||||||
// For the third pair, we encode the mix layer for N1, and the destination is N2
|
// For the third pair, we encode the mix layer for N1, and the destination is N2
|
||||||
// Entry gateway will simply forward the packet to N1 and processing will continue from there
|
// Entry gateway will simply forward the packet to N1 and processing will continue from there
|
||||||
for (idx, nodes) in route.windows(2).enumerate() {
|
for (idx, nodes) in route.windows(2).enumerate() {
|
||||||
let (range, stage_params) = mix_params.get_stage_params(idx + 1);
|
let (range, stage_params) = mix_params.get_stage_params(idx + 1);
|
||||||
// We know that we'll always get 4 nodes, so we can unwrap here
|
// We know that we'll always get DEFAULT_HOPS nodes, so we can unwrap here
|
||||||
let processing_node = nodes.last().unwrap();
|
let processing_node = nodes.last().unwrap();
|
||||||
let destination_node = nodes.first().unwrap();
|
let destination_node = nodes.first().unwrap();
|
||||||
let secret_key = x25519_dalek::StaticSecret::random();
|
|
||||||
stage_params.encode_mix_layer(
|
stage_params.encode_mix_layer(
|
||||||
|
rng,
|
||||||
&mut buffer[range],
|
&mut buffer[range],
|
||||||
&secret_key,
|
&processing_node.pub_key,
|
||||||
processing_node.pub_key,
|
|
||||||
destination_node.address.as_bytes(),
|
destination_node.address.as_bytes(),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(OutfoxPacket {
|
Ok(OutfoxPacket {
|
||||||
|
kem,
|
||||||
mix_params,
|
mix_params,
|
||||||
payload: buffer,
|
payload: buffer,
|
||||||
})
|
})
|
||||||
@@ -164,7 +173,7 @@ impl OutfoxPacket {
|
|||||||
pub fn decode_mix_layer(
|
pub fn decode_mix_layer(
|
||||||
&mut self,
|
&mut self,
|
||||||
layer: usize,
|
layer: usize,
|
||||||
mix_secret_key: &x25519_dalek::StaticSecret,
|
mix_secret_key: &PrivateKey,
|
||||||
) -> Result<Vec<u8>, OutfoxError> {
|
) -> Result<Vec<u8>, OutfoxError> {
|
||||||
let (range, params) = self.stage_params(layer);
|
let (range, params) = self.stage_params(layer);
|
||||||
let routing_data =
|
let routing_data =
|
||||||
|
|||||||
@@ -0,0 +1,201 @@
|
|||||||
|
// I took everything from sphinx to decouple the crates
|
||||||
|
|
||||||
|
use std::fmt::{self, Display, Formatter};
|
||||||
|
|
||||||
|
use libcrux_kem::{Algorithm, PublicKey};
|
||||||
|
|
||||||
|
use crate::error::OutfoxError;
|
||||||
|
|
||||||
|
pub const SECURITY_PARAMETER: usize = 16; // k in the Sphinx paper. Measured in bytes; 128 bits.
|
||||||
|
pub const DESTINATION_ADDRESS_LENGTH: usize = 2 * SECURITY_PARAMETER;
|
||||||
|
pub const IDENTIFIER_LENGTH: usize = SECURITY_PARAMETER;
|
||||||
|
pub const NODE_ADDRESS_LENGTH: usize = 2 * SECURITY_PARAMETER;
|
||||||
|
pub const DEFAULT_PAYLOAD_SIZE: usize = 1024;
|
||||||
|
|
||||||
|
// in paper I
|
||||||
|
pub type SURBIdentifier = [u8; IDENTIFIER_LENGTH];
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub struct Destination {
|
||||||
|
// address in theory could be changed to a vec<u8> as it does not need to be strictly DESTINATION_ADDRESS_LENGTH long
|
||||||
|
// but cannot be longer than that (assuming longest possible route)
|
||||||
|
pub address: DestinationAddressBytes,
|
||||||
|
pub identifier: SURBIdentifier,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Destination {
|
||||||
|
pub fn new(address: DestinationAddressBytes, identifier: SURBIdentifier) -> Self {
|
||||||
|
Self {
|
||||||
|
address,
|
||||||
|
identifier,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// in paper nu
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Hash)]
|
||||||
|
pub struct NodeAddressBytes([u8; NODE_ADDRESS_LENGTH]);
|
||||||
|
|
||||||
|
impl NodeAddressBytes {
|
||||||
|
pub fn as_base58_string(&self) -> String {
|
||||||
|
bs58::encode(&self.0).into_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_from_base58_string<S: Into<String>>(val: S) -> Result<Self, OutfoxError> {
|
||||||
|
let decoded = match bs58::decode(val.into()).into_vec() {
|
||||||
|
Ok(decoded) => decoded,
|
||||||
|
Err(e) => {
|
||||||
|
return Err(OutfoxError::InvalidRouting(format!(
|
||||||
|
"failed to decode node address from b58 string: {:?}",
|
||||||
|
e
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if decoded.len() != NODE_ADDRESS_LENGTH {
|
||||||
|
return Err(OutfoxError::InvalidRouting(
|
||||||
|
format!("decoded node address has invalid length").into(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut address_bytes = [0; NODE_ADDRESS_LENGTH];
|
||||||
|
address_bytes.copy_from_slice(&decoded[..]);
|
||||||
|
|
||||||
|
Ok(NodeAddressBytes(address_bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_from_byte_slice(b: &[u8]) -> Result<Self, OutfoxError> {
|
||||||
|
if b.len() != NODE_ADDRESS_LENGTH {
|
||||||
|
return Err(OutfoxError::InvalidRouting(
|
||||||
|
format!("received bytes got invalid length").into(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut address_bytes = [0; NODE_ADDRESS_LENGTH];
|
||||||
|
address_bytes.copy_from_slice(b);
|
||||||
|
|
||||||
|
Ok(NodeAddressBytes(address_bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_bytes(b: [u8; NODE_ADDRESS_LENGTH]) -> Self {
|
||||||
|
NodeAddressBytes(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// View this `NodeAddressBytes` as an array of bytes.
|
||||||
|
pub fn as_bytes(&self) -> &[u8; NODE_ADDRESS_LENGTH] {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert this `NodeAddressBytes` to an array of bytes.
|
||||||
|
pub fn to_bytes(&self) -> [u8; NODE_ADDRESS_LENGTH] {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for NodeAddressBytes {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
self.as_base58_string().fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Node {
|
||||||
|
pub kem: Algorithm,
|
||||||
|
pub address: NodeAddressBytes,
|
||||||
|
pub pub_key: PublicKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for Node {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
kem: self.kem,
|
||||||
|
address: self.address.clone(),
|
||||||
|
pub_key: PublicKey::decode(self.kem, &self.pub_key.encode()).unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::fmt::Debug for Node {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("Node")
|
||||||
|
.field("kem", &self.kem)
|
||||||
|
.field("address", &self.address)
|
||||||
|
.field("pub_key", &self.pub_key.encode())
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node {
|
||||||
|
pub fn new(kem: Algorithm, address: NodeAddressBytes, pub_key: PublicKey) -> Self {
|
||||||
|
Self {
|
||||||
|
kem,
|
||||||
|
address,
|
||||||
|
pub_key,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// in paper delta
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Hash)]
|
||||||
|
pub struct DestinationAddressBytes([u8; DESTINATION_ADDRESS_LENGTH]);
|
||||||
|
|
||||||
|
impl DestinationAddressBytes {
|
||||||
|
pub fn as_base58_string(&self) -> String {
|
||||||
|
bs58::encode(&self.0).into_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_from_base58_string<S: Into<String>>(val: S) -> Result<Self, OutfoxError> {
|
||||||
|
let decoded = match bs58::decode(val.into()).into_vec() {
|
||||||
|
Ok(decoded) => decoded,
|
||||||
|
Err(e) => {
|
||||||
|
return Err(OutfoxError::InvalidRouting(format!(
|
||||||
|
"failed to decode destination from b58 string: {:?}",
|
||||||
|
e
|
||||||
|
))
|
||||||
|
.into())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if decoded.len() != DESTINATION_ADDRESS_LENGTH {
|
||||||
|
return Err(OutfoxError::InvalidRouting(
|
||||||
|
format!("decoded destination address has invalid length",).into(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut address_bytes = [0; DESTINATION_ADDRESS_LENGTH];
|
||||||
|
address_bytes.copy_from_slice(&decoded[..]);
|
||||||
|
|
||||||
|
Ok(DestinationAddressBytes(address_bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_bytes(b: [u8; DESTINATION_ADDRESS_LENGTH]) -> Self {
|
||||||
|
DestinationAddressBytes(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_from_byte_slice(b: &[u8]) -> Result<Self, OutfoxError> {
|
||||||
|
if b.len() != DESTINATION_ADDRESS_LENGTH {
|
||||||
|
return Err(
|
||||||
|
OutfoxError::InvalidRouting(format!("received bytes got invalid length")).into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut address_bytes = [0; DESTINATION_ADDRESS_LENGTH];
|
||||||
|
address_bytes.copy_from_slice(b);
|
||||||
|
|
||||||
|
Ok(DestinationAddressBytes(address_bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// View this `DestinationAddressBytes` as an array of bytes.
|
||||||
|
pub fn as_bytes_ref(&self) -> &[u8; DESTINATION_ADDRESS_LENGTH] {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert this `DestinationAddressBytes` to an array of bytes.
|
||||||
|
pub fn as_bytes(&self) -> [u8; DESTINATION_ADDRESS_LENGTH] {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for DestinationAddressBytes {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
self.as_base58_string().fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
+193
-136
@@ -9,71 +9,64 @@ mod tests {
|
|||||||
repeat_with(|| fastrand::u8(..)).take(n).collect()
|
repeat_with(|| fastrand::u8(..)).take(n).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use libcrux_kem::key_gen;
|
||||||
use nym_outfox::packet::OutfoxPacket;
|
use nym_outfox::packet::OutfoxPacket;
|
||||||
use sphinx_packet::constants::NODE_ADDRESS_LENGTH;
|
|
||||||
use sphinx_packet::crypto::{PrivateKey, PublicKey};
|
use nym_outfox::route::{
|
||||||
use sphinx_packet::route::Destination;
|
Destination, DestinationAddressBytes, Node, NodeAddressBytes, NODE_ADDRESS_LENGTH,
|
||||||
use sphinx_packet::route::DestinationAddressBytes;
|
};
|
||||||
use sphinx_packet::route::Node;
|
|
||||||
use sphinx_packet::route::NodeAddressBytes;
|
|
||||||
|
|
||||||
use nym_outfox::format::*;
|
use nym_outfox::format::*;
|
||||||
use nym_outfox::lion::*;
|
use nym_outfox::lion::*;
|
||||||
|
|
||||||
pub fn keygen() -> (PrivateKey, PublicKey) {
|
|
||||||
let private_key = PrivateKey::random();
|
|
||||||
let public_key = PublicKey::from(&private_key);
|
|
||||||
(private_key, public_key)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_encode_decode() {
|
fn test_encode_decode() {
|
||||||
let mix_params = MixStageParameters {
|
for kem in [
|
||||||
routing_information_length_bytes: 32,
|
libcrux_kem::Algorithm::X25519,
|
||||||
remaining_header_length_bytes: (32 + 16 + 32) * 4,
|
libcrux_kem::Algorithm::XWingKemDraft06,
|
||||||
payload_length_bytes: 1024, // 1kb
|
libcrux_kem::Algorithm::MlKem768,
|
||||||
};
|
] {
|
||||||
|
let mix_params = MixStageParameters {
|
||||||
|
kem: kem,
|
||||||
|
routing_information_length_bytes: 32,
|
||||||
|
remaining_header_length_bytes: (32 + 16 + 32) * 4,
|
||||||
|
payload_length_bytes: 1024, // 1kb
|
||||||
|
};
|
||||||
|
|
||||||
let user_secret = x25519_dalek::StaticSecret::random();
|
let mut rng = rand::rng();
|
||||||
let mix_secret = x25519_dalek::StaticSecret::random();
|
let (mix_decapsulation_key, mix_encapsulation_key) = key_gen(kem, &mut rng).unwrap();
|
||||||
let mix_public_key = x25519_dalek::PublicKey::from(&mix_secret);
|
|
||||||
|
|
||||||
let routing = [0; 32];
|
let routing = [0; 32];
|
||||||
let destination = [0; 32];
|
let destination = [0; 32];
|
||||||
|
|
||||||
let buffer = randombytes(mix_params.incoming_packet_length());
|
let buffer = randombytes(mix_params.incoming_packet_length());
|
||||||
|
|
||||||
let mut new_buffer = buffer.clone();
|
let mut new_buffer = buffer.clone();
|
||||||
|
|
||||||
let node_address_bytes = NodeAddressBytes::from_bytes(routing);
|
let node_address_bytes = NodeAddressBytes::from_bytes(routing);
|
||||||
let mix_public_key = PublicKey::from(*mix_public_key.as_bytes());
|
|
||||||
|
|
||||||
let node = Node::new(node_address_bytes, mix_public_key);
|
let node = Node::new(kem, node_address_bytes, mix_encapsulation_key);
|
||||||
|
|
||||||
let _ = mix_params
|
let _ = mix_params
|
||||||
.encode_mix_layer(
|
.encode_mix_layer(&mut rng, &mut new_buffer[..], &node.pub_key, &destination)
|
||||||
&mut new_buffer[..],
|
.unwrap();
|
||||||
&user_secret,
|
|
||||||
node.pub_key,
|
|
||||||
&destination,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_ne!(
|
assert_ne!(
|
||||||
new_buffer[mix_params.payload_range()],
|
new_buffer[mix_params.payload_range()],
|
||||||
buffer[mix_params.payload_range()]
|
buffer[mix_params.payload_range()]
|
||||||
);
|
);
|
||||||
assert_ne!(new_buffer[mix_params.routing_data_range()], routing[..]);
|
assert_ne!(new_buffer[mix_params.routing_data_range()], routing[..]);
|
||||||
|
|
||||||
let _ = mix_params
|
let _ = mix_params
|
||||||
.decode_mix_layer(&mut new_buffer[..], &mix_secret)
|
.decode_mix_layer(&mut new_buffer[..], &mix_decapsulation_key)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
new_buffer[mix_params.payload_range()],
|
new_buffer[mix_params.payload_range()],
|
||||||
buffer[mix_params.payload_range()]
|
buffer[mix_params.payload_range()]
|
||||||
);
|
);
|
||||||
assert_eq!(new_buffer[mix_params.routing_data_range()], routing[..]);
|
assert_eq!(new_buffer[mix_params.routing_data_range()], routing[..]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -95,113 +88,177 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_packet_params_short() {
|
fn test_packet_params_short() {
|
||||||
let (node1_pk, node1_pub) = keygen();
|
let mut rng = rand::rng();
|
||||||
let node1 = Node::new(
|
for kem in [
|
||||||
NodeAddressBytes::from_bytes([0u8; NODE_ADDRESS_LENGTH]),
|
libcrux_kem::Algorithm::X25519,
|
||||||
node1_pub,
|
libcrux_kem::Algorithm::XWingKemDraft06,
|
||||||
);
|
libcrux_kem::Algorithm::MlKem768,
|
||||||
let (node2_pk, node2_pub) = keygen();
|
] {
|
||||||
let node2 = Node::new(
|
let (entry_pk, entry_pub) = key_gen(kem, &mut rng).unwrap();
|
||||||
NodeAddressBytes::from_bytes([1u8; NODE_ADDRESS_LENGTH]),
|
let entry = Node::new(
|
||||||
node2_pub,
|
kem,
|
||||||
);
|
NodeAddressBytes::from_bytes([8u8; NODE_ADDRESS_LENGTH]),
|
||||||
let (node3_pk, node3_pub) = keygen();
|
entry_pub,
|
||||||
let node3 = Node::new(
|
);
|
||||||
NodeAddressBytes::from_bytes([2u8; NODE_ADDRESS_LENGTH]),
|
let (node1_pk, node1_pub) = key_gen(kem, &mut rng).unwrap();
|
||||||
node3_pub,
|
let node1 = Node::new(
|
||||||
);
|
kem,
|
||||||
|
NodeAddressBytes::from_bytes([0u8; NODE_ADDRESS_LENGTH]),
|
||||||
|
node1_pub,
|
||||||
|
);
|
||||||
|
let (node2_pk, node2_pub) = key_gen(kem, &mut rng).unwrap();
|
||||||
|
let node2 = Node::new(
|
||||||
|
kem,
|
||||||
|
NodeAddressBytes::from_bytes([1u8; NODE_ADDRESS_LENGTH]),
|
||||||
|
node2_pub,
|
||||||
|
);
|
||||||
|
let (node3_pk, node3_pub) = key_gen(kem, &mut rng).unwrap();
|
||||||
|
let node3 = Node::new(
|
||||||
|
kem,
|
||||||
|
NodeAddressBytes::from_bytes([2u8; NODE_ADDRESS_LENGTH]),
|
||||||
|
node3_pub,
|
||||||
|
);
|
||||||
|
|
||||||
let (gateway_pk, gateway_pub) = keygen();
|
let (exit_pk, exit_pub) = key_gen(kem, &mut rng).unwrap();
|
||||||
let gateway = Node::new(
|
let exit = Node::new(
|
||||||
NodeAddressBytes::from_bytes([3u8; NODE_ADDRESS_LENGTH]),
|
kem,
|
||||||
gateway_pub,
|
NodeAddressBytes::from_bytes([3u8; NODE_ADDRESS_LENGTH]),
|
||||||
);
|
exit_pub,
|
||||||
|
);
|
||||||
|
|
||||||
let destination = Destination::new(
|
let destination = Destination::new(
|
||||||
DestinationAddressBytes::from_bytes([9u8; NODE_ADDRESS_LENGTH]),
|
DestinationAddressBytes::from_bytes([9u8; NODE_ADDRESS_LENGTH]),
|
||||||
[0u8; 16],
|
[0u8; 16],
|
||||||
);
|
);
|
||||||
|
|
||||||
let route = [node1, node2.clone(), node3.clone(), gateway.clone()];
|
let route = [
|
||||||
|
entry,
|
||||||
|
node1.clone(),
|
||||||
|
node2.clone(),
|
||||||
|
node3.clone(),
|
||||||
|
exit.clone(),
|
||||||
|
];
|
||||||
|
|
||||||
let payload = vec![0, 0, 1, 1, 1, 0, 0];
|
let payload = vec![0, 0, 1, 1, 1, 0, 0];
|
||||||
|
|
||||||
let packet =
|
let packet = OutfoxPacket::build(
|
||||||
OutfoxPacket::build(&payload, &route, &destination, Some(payload.len())).unwrap();
|
&mut rng,
|
||||||
let packet_bytes = packet.to_bytes().unwrap();
|
kem,
|
||||||
println!(
|
&payload,
|
||||||
"packet bytes length, {}, declared {}",
|
&route,
|
||||||
packet_bytes.len(),
|
&destination,
|
||||||
packet.len()
|
Some(payload.len()),
|
||||||
);
|
)
|
||||||
|
.unwrap();
|
||||||
|
let packet_bytes = packet.to_bytes().unwrap();
|
||||||
|
println!(
|
||||||
|
"packet bytes length, {}, declared {}",
|
||||||
|
packet_bytes.len(),
|
||||||
|
packet.len()
|
||||||
|
);
|
||||||
|
|
||||||
let mut packet = OutfoxPacket::try_from(packet_bytes.as_slice()).unwrap();
|
let mut packet = OutfoxPacket::try_from((kem, packet_bytes.as_slice())).unwrap();
|
||||||
|
|
||||||
let next_address = packet.decode_next_layer(&node1_pk).unwrap();
|
let next_address = packet.decode_next_layer(&entry_pk).unwrap();
|
||||||
assert_eq!(&next_address, node2.address.as_bytes());
|
assert_eq!(&next_address, node1.address.as_bytes());
|
||||||
let next_address = packet.decode_next_layer(&node2_pk).unwrap();
|
let next_address = packet.decode_next_layer(&node1_pk).unwrap();
|
||||||
assert_eq!(&next_address, node3.address.as_bytes());
|
assert_eq!(&next_address, node2.address.as_bytes());
|
||||||
let next_address = packet.decode_next_layer(&node3_pk).unwrap();
|
let next_address = packet.decode_next_layer(&node2_pk).unwrap();
|
||||||
assert_eq!(&next_address, gateway.address.as_bytes());
|
assert_eq!(&next_address, node3.address.as_bytes());
|
||||||
let destination_address = packet.decode_next_layer(&gateway_pk).unwrap();
|
let next_address = packet.decode_next_layer(&node3_pk).unwrap();
|
||||||
assert_eq!(destination_address, destination.address.as_bytes());
|
assert_eq!(&next_address, exit.address.as_bytes());
|
||||||
|
let destination_address = packet.decode_next_layer(&exit_pk).unwrap();
|
||||||
|
assert_eq!(destination_address, destination.address.as_bytes());
|
||||||
|
|
||||||
assert_eq!(payload, packet.recover_plaintext().unwrap());
|
assert_eq!(payload, packet.recover_plaintext().unwrap());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_packet_params_long() {
|
fn test_packet_params_long() {
|
||||||
let (node1_pk, node1_pub) = keygen();
|
let mut rng = rand::rng();
|
||||||
let node1 = Node::new(
|
for kem in [
|
||||||
NodeAddressBytes::from_bytes([0u8; NODE_ADDRESS_LENGTH]),
|
libcrux_kem::Algorithm::X25519,
|
||||||
node1_pub,
|
libcrux_kem::Algorithm::XWingKemDraft06,
|
||||||
);
|
libcrux_kem::Algorithm::MlKem768,
|
||||||
let (node2_pk, node2_pub) = keygen();
|
] {
|
||||||
let node2 = Node::new(
|
let (entry_pk, entry_pub) = key_gen(kem, &mut rng).unwrap();
|
||||||
NodeAddressBytes::from_bytes([1u8; NODE_ADDRESS_LENGTH]),
|
let entry = Node::new(
|
||||||
node2_pub,
|
kem,
|
||||||
);
|
NodeAddressBytes::from_bytes([8u8; NODE_ADDRESS_LENGTH]),
|
||||||
let (node3_pk, node3_pub) = keygen();
|
entry_pub,
|
||||||
let node3 = Node::new(
|
);
|
||||||
NodeAddressBytes::from_bytes([2u8; NODE_ADDRESS_LENGTH]),
|
let (node1_pk, node1_pub) = key_gen(kem, &mut rng).unwrap();
|
||||||
node3_pub,
|
let node1 = Node::new(
|
||||||
);
|
kem,
|
||||||
|
NodeAddressBytes::from_bytes([0u8; NODE_ADDRESS_LENGTH]),
|
||||||
|
node1_pub,
|
||||||
|
);
|
||||||
|
let (node2_pk, node2_pub) = key_gen(kem, &mut rng).unwrap();
|
||||||
|
let node2 = Node::new(
|
||||||
|
kem,
|
||||||
|
NodeAddressBytes::from_bytes([1u8; NODE_ADDRESS_LENGTH]),
|
||||||
|
node2_pub,
|
||||||
|
);
|
||||||
|
let (node3_pk, node3_pub) = key_gen(kem, &mut rng).unwrap();
|
||||||
|
let node3 = Node::new(
|
||||||
|
kem,
|
||||||
|
NodeAddressBytes::from_bytes([2u8; NODE_ADDRESS_LENGTH]),
|
||||||
|
node3_pub,
|
||||||
|
);
|
||||||
|
|
||||||
let (gateway_pk, gateway_pub) = keygen();
|
let (exit_pk, exit_pub) = key_gen(kem, &mut rng).unwrap();
|
||||||
let gateway = Node::new(
|
let exit = Node::new(
|
||||||
NodeAddressBytes::from_bytes([3u8; NODE_ADDRESS_LENGTH]),
|
kem,
|
||||||
gateway_pub,
|
NodeAddressBytes::from_bytes([3u8; NODE_ADDRESS_LENGTH]),
|
||||||
);
|
exit_pub,
|
||||||
|
);
|
||||||
|
|
||||||
let destination = Destination::new(
|
let destination = Destination::new(
|
||||||
DestinationAddressBytes::from_bytes([9u8; NODE_ADDRESS_LENGTH]),
|
DestinationAddressBytes::from_bytes([9u8; NODE_ADDRESS_LENGTH]),
|
||||||
[0u8; 16],
|
[0u8; 16],
|
||||||
);
|
);
|
||||||
|
|
||||||
let route = [node1, node2.clone(), node3.clone(), gateway.clone()];
|
let route = [
|
||||||
|
entry,
|
||||||
|
node1.clone(),
|
||||||
|
node2.clone(),
|
||||||
|
node3.clone(),
|
||||||
|
exit.clone(),
|
||||||
|
];
|
||||||
|
|
||||||
let payload = randombytes(2048);
|
let payload = randombytes(2048);
|
||||||
|
|
||||||
let packet =
|
let packet = OutfoxPacket::build(
|
||||||
OutfoxPacket::build(&payload, &route, &destination, Some(payload.len())).unwrap();
|
&mut rng,
|
||||||
let packet_bytes = packet.to_bytes().unwrap();
|
kem,
|
||||||
println!(
|
&payload,
|
||||||
"packet bytes length, {}, declared {}",
|
&route,
|
||||||
packet_bytes.len(),
|
&destination,
|
||||||
packet.len()
|
Some(payload.len()),
|
||||||
);
|
)
|
||||||
|
.unwrap();
|
||||||
|
let packet_bytes = packet.to_bytes().unwrap();
|
||||||
|
println!(
|
||||||
|
"packet bytes length, {}, declared {}",
|
||||||
|
packet_bytes.len(),
|
||||||
|
packet.len()
|
||||||
|
);
|
||||||
|
|
||||||
let mut packet = OutfoxPacket::try_from(packet_bytes.as_slice()).unwrap();
|
let mut packet = OutfoxPacket::try_from((kem, packet_bytes.as_slice())).unwrap();
|
||||||
|
|
||||||
let next_address = packet.decode_next_layer(&node1_pk).unwrap();
|
let next_address = packet.decode_next_layer(&entry_pk).unwrap();
|
||||||
assert_eq!(&next_address, node2.address.as_bytes());
|
assert_eq!(&next_address, node1.address.as_bytes());
|
||||||
let next_address = packet.decode_next_layer(&node2_pk).unwrap();
|
let next_address = packet.decode_next_layer(&node1_pk).unwrap();
|
||||||
assert_eq!(&next_address, node3.address.as_bytes());
|
assert_eq!(&next_address, node2.address.as_bytes());
|
||||||
let next_address = packet.decode_next_layer(&node3_pk).unwrap();
|
let next_address = packet.decode_next_layer(&node2_pk).unwrap();
|
||||||
assert_eq!(&next_address, gateway.address.as_bytes());
|
assert_eq!(&next_address, node3.address.as_bytes());
|
||||||
let destination_address = packet.decode_next_layer(&gateway_pk).unwrap();
|
let next_address = packet.decode_next_layer(&node3_pk).unwrap();
|
||||||
assert_eq!(destination_address, destination.address.as_bytes());
|
assert_eq!(&next_address, exit.address.as_bytes());
|
||||||
|
let destination_address = packet.decode_next_layer(&exit_pk).unwrap();
|
||||||
|
assert_eq!(destination_address, destination.address.as_bytes());
|
||||||
|
|
||||||
assert_eq!(payload, packet.recover_plaintext().unwrap());
|
assert_eq!(payload, packet.recover_plaintext().unwrap());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user