Compare commits

..

116 Commits

Author SHA1 Message Date
Yana 28b4fe7e7e add 10 recommended nodes 2025-06-05 12:33:43 +03:00
Yana 9479d2a383 Add recommended nodes 2025-06-04 19:47:53 +03:00
Yana 886b4410aa Fix open in new tab click on NodeTable 2025-06-03 14:28:17 +03:00
Yana b51358fb12 Style fixes 2025-05-22 14:24:24 +03:00
Yana 53e3acaa37 Add countries and locations to WorldMap 2025-05-21 17:11:52 +03:00
Yana 978817baf7 fix build 2025-05-15 19:20:16 +03:00
Yana 9319a5ec04 fix self-bond, redirect articles to nym/blog 2025-05-15 19:15:29 +03:00
Yana 3186db2915 style fixes 2025-05-14 20:47:26 +03:00
Yana ff7671f28a update copy 2025-05-14 20:38:07 +03:00
Yana cbe8eec2a4 fix dark mode font color 2025-05-14 19:53:07 +03:00
Yana 42f9edd408 Add self-bond and operating costs to NodeTable 2025-05-14 19:40:31 +03:00
Yana 128cf7c070 Add colors on uptime 2025-05-09 15:46:50 +03:00
Yana 79e5004849 revamp NodeTable 2025-05-09 15:27:54 +03:00
Yana 0d6722f9f5 'Change footer version to 2.2 2025-05-08 15:17:28 +03:00
Yana d458df9c34 fix build 2025-05-08 15:08:48 +03:00
Yana 7a8ac59a36 Add default sorting by country to Node tables 2025-05-08 14:56:04 +03:00
Yana ad3eb7a84c fix build 2025-05-07 19:54:09 +03:00
Yana 135f248eba Replace spectreDao delegations 2025-05-07 18:59:05 +03:00
Yana 7012bf9886 Add node count on every quick filter 2025-05-06 16:25:40 +03:00
Yana 88aa32ddeb Fix advanced filtering UI 2025-05-06 16:15:23 +03:00
Yana 7c1c9976f0 fix build 2025-05-04 19:27:47 +03:00
Yana 4ee7f7eaf5 Fix saturation filter 2025-05-04 19:23:35 +03:00
Yana 778772d96a fix build 2025-05-04 19:16:30 +03:00
Yana 5b791b41aa Add advanced filters 2025-05-04 19:13:34 +03:00
Yana 4b7e51fc3b Add quick filters on NodeTable 2025-05-04 11:27:29 +03:00
Yana 0a42dd3e0d fix mobile map 2025-04-22 20:20:44 +03:00
Yana 7cf49f642d fix images 2025-04-22 19:47:40 +03:00
Yana 089ab65dd7 Fix maps 2025-04-22 18:51:29 +03:00
Yana c1fabae770 Clean up 2025-04-17 18:25:43 +03:00
Yana 3ed7cfa381 Replace SpectreDao on AccountPageButtonGroup 2025-04-17 18:21:30 +03:00
Yana 4fe83da99d Replace SpectreDao api in Staking Table 2025-04-17 18:16:13 +03:00
Yana 4f81fc7400 Replace SpectreDao api on Magic Search 2025-04-17 17:55:52 +03:00
Yana 6d601ca654 Replace SpectreDao api on Stakers Card 2025-04-17 17:46:35 +03:00
Yana cea3ad9908 Add dark mode on error cards 2025-04-17 17:36:27 +03:00
Yana e4ecd099cc Add dark mode on error cards 2025-04-17 17:28:08 +03:00
Yana 0723542c39 clean up 2025-04-16 21:20:14 +03:00
Yana 523e559ff8 clean up 2025-04-16 21:17:15 +03:00
Yana 02b27573de clean up 2025-04-16 21:08:31 +03:00
Yana 8f229737a3 Replace SpectreDao on NodeTable and Node page 2025-04-16 21:06:12 +03:00
Yana 1afd13d6e0 Clean up 2025-04-16 15:27:53 +03:00
Yana df10b5595a Add styles 2025-04-16 15:23:05 +03:00
Yana 443031ba66 test data fetching 2025-04-16 13:37:35 +03:00
Yana 8d340a49d3 fix data fetching 2025-04-16 09:57:27 +03:00
Yana e0925d3c7f clean up 2025-04-16 08:40:34 +03:00
Yana 89d391da29 fix build 2025-04-16 08:13:21 +03:00
Yana cc2d7d34d2 reset last changes 2025-04-16 08:05:04 +03:00
Yana 969070f938 fix build, fix map sizes 2025-04-15 21:38:05 +03:00
Yana 3dfcae9369 fix build 2025-04-15 21:04:58 +03:00
Yana 32a4bf1172 fix build 2025-04-15 20:54:37 +03:00
Yana 433cac8c58 Fix map sizing 2025-04-15 18:15:00 +03:00
Yana 4fc64a072c Add WorldMap 2025-04-15 16:47:37 +03:00
Yana Matrosova 2c7df5766c Merge pull request #5706 from nymtech/yana/explorer-caching
Yana/explorer caching
2025-04-14 10:03:44 -07:00
Yana 7ca2559f99 Add caching on tanstack queries
clean up

Another try

clean up

fix build

fix build

fix build

fix build

Refactor Node page to accept identity_key in params
fix build

fix build

fix buggy data on landing page graphs

Try fix gas fee for redeem all rewards

Another try to fix gas fee for redeem rewards

Add fees "auto" to the cosmWasm client with offline signer

comment out unused option

add getOfflineSigner dependency to the callback fn

comment out for good

clean up, optimise homepage layout

Dark theme
fix build

fix build

add fixes
Rebase onto develop, fix lint error

fix build

Fix tooltip

Fix switch button on mobile header

fix build

clean up

fix build

Fix switch component

fix build

Add moniker to Magic Search, fix tooltip hover on landing page

refactor urls

fix build

edit placeholder

Fix styles

fix error message
2025-04-14 17:01:44 +03:00
Jędrzej Stuczyński 84db9f6bcd chore: rename 'identity' module to 'ed25519' and 'encryption' to 'x25519' (#5707) 2025-04-13 11:58:25 +01:00
dynco-nym 660463908d Expand /v3/nym-nodes with geodata (#5686)
* Expand /v3/nym-nodes
- includes node description and geodata
- expanded scope of included geodata

* Fetch geodata for all nodes

* Bump package version
2025-04-10 21:12:33 +02:00
dependabot[bot] 0be844e015 build(deps): bump crossbeam-channel from 0.5.14 to 0.5.15 (#5702) 2025-04-10 20:06:50 +02:00
Yana Matrosova efa6e7d7c7 Merge pull request #5669 from nymtech/yana/explorer-caching
Yana/explorer caching
2025-04-10 18:41:31 +03:00
dynco-nym 33c783bb7c Bump package version 2025-04-10 17:22:21 +02:00
Bogdan-Ștefan Neacşu 16059211b9 Add contains ticketbook data db query (#5670)
* Add contains ticketbook data db query

* Fix clippy

* Use exists for better performance
2025-04-10 18:21:50 +03:00
Yana bb6c920767 fix build 2025-04-10 17:24:40 +03:00
Yana 8c4df963c9 Fix switch button on mobile header 2025-04-10 17:23:04 +03:00
Yana af737596ca Fix tooltip 2025-04-10 16:50:45 +03:00
Jędrzej Stuczyński af2c4f50b6 Feature/updated sphinx payload keys (#5698)
* removed support for legacy packet types from NymCodec

I think nodes had plenty of time to upgrade given versioned variant was introduced in 2022

* temp: use local sphinx packet for development

* introduce new messages that use more efficient reply surbs encoding

* checks for incorrect encoding

* generate correct message depending on config value

* fixed current packet version

* made packet type selection configurable

* updated sphinx packet crate to the published version

* fixed wasm build

* fixes in outfox due to sphinx api changes

* additional tests

* clippy

* fixed log/tracing import
2025-04-10 13:43:29 +01:00
Jędrzej Stuczyński 02ed64557d chore: removed old explorer-api (#5701) 2025-04-10 11:26:24 +01:00
Yana 38dabd8d0d fix build 2025-04-10 11:38:43 +03:00
Yana d9de5cfa33 Rebase onto develop, fix lint error 2025-04-10 11:29:13 +03:00
Yana bdfbfde463 add fixes 2025-04-10 11:14:58 +03:00
Yana 5179f38ad2 fix build 2025-04-10 11:14:54 +03:00
Yana f4e9abcd22 fix build 2025-04-10 11:14:54 +03:00
Yana 46ebd84b02 Dark theme 2025-04-10 11:14:54 +03:00
Yana d8d2f99a18 clean up, optimise homepage layout 2025-04-10 11:14:49 +03:00
Yana cd3ec5f3bd comment out for good 2025-04-10 11:14:49 +03:00
Yana 32a16ef025 add getOfflineSigner dependency to the callback fn 2025-04-10 11:14:48 +03:00
Yana 6af4e44f55 comment out unused option 2025-04-10 11:14:48 +03:00
Yana 3cddc594b4 Add fees "auto" to the cosmWasm client with offline signer 2025-04-10 11:14:48 +03:00
Yana d11aaed392 Another try to fix gas fee for redeem rewards 2025-04-10 11:14:48 +03:00
Yana 1bead28150 Try fix gas fee for redeem all rewards 2025-04-10 11:14:48 +03:00
Yana 735bed5cd7 fix buggy data on landing page graphs 2025-04-10 11:14:48 +03:00
Yana 12e0d34885 fix build 2025-04-10 11:14:48 +03:00
Yana 43af3b8a3b fix build 2025-04-10 11:14:48 +03:00
Yana 8ff96b11c9 Refactor Node page to accept identity_key in params 2025-04-10 11:14:48 +03:00
Yana df453158d6 fix build 2025-04-10 11:14:36 +03:00
Yana abeeadb661 fix build 2025-04-10 11:14:36 +03:00
Yana 752fe7fa0f fix build 2025-04-10 11:14:36 +03:00
Yana c5ec682088 fix build 2025-04-10 11:14:36 +03:00
Yana 58a569cd26 clean up 2025-04-10 11:14:36 +03:00
Yana 2e767a2586 Another try 2025-04-10 11:14:35 +03:00
Yana dc772d8759 clean up 2025-04-10 11:14:35 +03:00
Yana 9e70c7a32d Add caching on tanstack queries 2025-04-10 11:14:35 +03:00
Jon Häggblad ba5e86e842 Bump the nym-vpn deb metapackage to 1.0 (#5697) 2025-04-09 18:07:55 +02:00
Tommy Verrall b7313656e9 Merge pull request #5699 from nymtech/fix/sign-in-page-wallet
Allow copy and paste on logins fields for the wallet
2025-04-09 15:15:28 +01:00
Tommy Verrall 2eb695088f linting and yarn
- modify log screen
2025-04-09 16:14:11 +02:00
Tommy Verrall eb612d47c0 Allow copy and paste on logins
- allow shell open for linking - some platforms it's not working as expected
2025-04-09 14:55:12 +02:00
benedetta davico 2ba7b26e5d Merge pull request #5659 from nymtech/benny/revamp-api-tests
Adding fresh nym-api tests and workflow
2025-04-09 13:13:24 +02:00
Tommy Verrall 4cd0f7b56f Merge pull request #5687 from nymtech/feature/test-v2
Tauri V2 - Wallet Migration
2025-04-09 12:09:41 +01:00
benedetta davico 7de346cf89 add env 2025-04-09 10:07:55 +02:00
benedetta davico d6c40aee01 add env 2025-04-09 10:07:49 +02:00
benedetta davico 0841b8701d change path 2025-04-08 19:04:47 +02:00
benedetta davico 7ae228d8f4 change path 2025-04-08 19:03:58 +02:00
benedetta davico 916d33c8c0 Update nym-api-integration-tests.yml 2025-04-08 18:55:57 +02:00
benedetta davico 9b4b2d1a46 Update Makefile 2025-04-08 18:55:25 +02:00
benedettadavico aef0a52c4b fix workflow typo 2025-04-08 18:49:40 +02:00
benedettadavico f282ffd8a6 remove missed line 2025-04-08 18:42:44 +02:00
benedettadavico dfbeb8b1f8 reformatting, tidying up 2025-04-08 18:38:18 +02:00
benedettadavico fc06fe39a2 more clippy fixes 2025-04-08 17:43:36 +02:00
benedettadavico caa94c142f fix clippy 2025-04-08 17:15:47 +02:00
benedettadavico 1a5c54084e fmt 2025-04-08 17:01:46 +02:00
benedettadavico 49d203e18d better response handling 2025-04-08 16:59:30 +02:00
benedetta davico 9225e0a630 Merge branch 'develop' into benny/revamp-api-tests 2025-04-08 15:43:31 +02:00
benedettadavico 36a4d96f34 cargo fmt 2025-04-08 13:48:42 +02:00
benedettadavico 139c911350 use env var for api url and make asserts uniform 2025-04-08 13:40:17 +02:00
benedettadavico bfddc1e4c1 clean up the test dir 2025-04-08 11:56:45 +02:00
benedettadavico 080d75204e first commit to cleaning up nym-api tests 2025-04-08 11:56:45 +02:00
benedettadavico edfe29b738 bump versions 2025-04-08 09:46:48 +02:00
dynco-nym 0d4188785b Fetch geodata for all nodes 2025-04-04 13:00:25 +02:00
dynco-nym 86c05267c2 Expand /v3/nym-nodes
- includes node description and geodata
- expanded scope of included geodata
2025-04-03 22:45:28 +02:00
363 changed files with 21008 additions and 22059 deletions
+2
View File
@@ -102,6 +102,8 @@ jobs:
- name: Run all tests
if: contains(matrix.os, 'ubuntu')
uses: actions-rs/cargo@v1
env:
NYM_API: https://sandbox-nym-api1.nymtech.net/api
with:
command: test
args: --workspace
@@ -0,0 +1,47 @@
name: Integration Tests
on:
pull_request:
paths:
- "nym-api/**"
- "tests/**"
workflow_dispatch:
jobs:
integration-tests:
runs-on: ubuntu-latest
env:
API_BASE_URL: http://localhost:8000
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
- name: Install dependencies
run: sudo apt-get update && sudo apt-get install -y pkg-config libssl-dev
- name: Build nym-api
run: cargo build --package nym-api
- name: Run nym-api in the background
run: |
./target/debug/nym-api &
- name: Wait for nym-api to come alive
run: |
for i in {1..20}; do
curl -sSf http://localhost:8000/v1/status/config-score-details && break
echo "Waiting for nym-api to start..."
sleep 2
done
- name: Run integration tests
env:
NYM_API: https://sandbox-nym-api1.nymtech.net/api
run: cargo test --test public-api-tests -- --nocapture
Generated
+21 -51
View File
@@ -1603,9 +1603,9 @@ dependencies = [
[[package]]
name = "crossbeam-channel"
version = "0.5.14"
version = "0.5.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471"
checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
dependencies = [
"crossbeam-utils",
]
@@ -2185,6 +2185,12 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
[[package]]
name = "dotenv"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
[[package]]
name = "dotenvy"
version = "0.15.7"
@@ -4697,7 +4703,7 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
[[package]]
name = "nym-api"
version = "1.1.55"
version = "1.1.56"
dependencies = [
"anyhow",
"async-trait",
@@ -4708,6 +4714,7 @@ dependencies = [
"bip39",
"bs58",
"cfg-if",
"chrono",
"clap",
"console-subscriber",
"cosmwasm-std",
@@ -4717,6 +4724,7 @@ dependencies = [
"cw4",
"dashmap",
"dirs",
"dotenv",
"futures",
"getset",
"humantime-serde",
@@ -4949,7 +4957,7 @@ dependencies = [
[[package]]
name = "nym-cli"
version = "1.1.52"
version = "1.1.53"
dependencies = [
"anyhow",
"base64 0.22.1",
@@ -5032,7 +5040,7 @@ dependencies = [
[[package]]
name = "nym-client"
version = "1.1.52"
version = "1.1.53"
dependencies = [
"bs58",
"clap",
@@ -5074,7 +5082,6 @@ dependencies = [
"async-trait",
"base64 0.22.1",
"bs58",
"cfg-if",
"clap",
"comfy-table",
"futures",
@@ -5089,12 +5096,10 @@ dependencies = [
"nym-client-core-gateways-storage",
"nym-client-core-surb-storage",
"nym-config",
"nym-country-group",
"nym-credential-storage",
"nym-credentials-interface",
"nym-crypto",
"nym-ecash-time",
"nym-explorer-client",
"nym-gateway-client",
"nym-gateway-requests",
"nym-http-api-client",
@@ -5115,7 +5120,6 @@ dependencies = [
"serde_json",
"sha2 0.10.8",
"si-scale",
"tap",
"tempfile",
"thiserror 2.0.12",
"time",
@@ -5137,7 +5141,6 @@ version = "0.1.0"
dependencies = [
"humantime-serde",
"nym-config",
"nym-country-group",
"nym-pemstore",
"nym-sphinx-addressing",
"nym-sphinx-params",
@@ -5279,14 +5282,6 @@ dependencies = [
"vergen",
]
[[package]]
name = "nym-country-group"
version = "0.1.0"
dependencies = [
"serde",
"tracing",
]
[[package]]
name = "nym-cpp-ffi"
version = "0.1.2"
@@ -5563,31 +5558,6 @@ dependencies = [
"utoipa",
]
[[package]]
name = "nym-explorer-api-requests"
version = "0.1.0"
dependencies = [
"nym-api-requests",
"nym-contracts-common",
"nym-mixnet-contract-common",
"schemars",
"serde",
"ts-rs",
]
[[package]]
name = "nym-explorer-client"
version = "0.1.0"
dependencies = [
"nym-explorer-api-requests",
"reqwest 0.12.15",
"serde",
"thiserror 2.0.12",
"tokio",
"tracing",
"url",
]
[[package]]
name = "nym-ffi-shared"
version = "0.2.1"
@@ -6067,7 +6037,7 @@ dependencies = [
[[package]]
name = "nym-network-requester"
version = "1.1.53"
version = "1.1.54"
dependencies = [
"addr",
"anyhow",
@@ -6118,7 +6088,7 @@ dependencies = [
[[package]]
name = "nym-node"
version = "1.8.0"
version = "1.9.0"
dependencies = [
"anyhow",
"arc-swap",
@@ -6251,7 +6221,7 @@ dependencies = [
[[package]]
name = "nym-node-status-api"
version = "2.0.0"
version = "2.1.0"
dependencies = [
"ammonia",
"anyhow",
@@ -6267,7 +6237,6 @@ dependencies = [
"nym-bin-common",
"nym-contracts-common",
"nym-crypto",
"nym-explorer-client",
"nym-http-api-client",
"nym-network-defaults",
"nym-node-metrics",
@@ -6513,7 +6482,7 @@ dependencies = [
[[package]]
name = "nym-socks5-client"
version = "1.1.52"
version = "1.1.53"
dependencies = [
"bs58",
"clap",
@@ -6676,6 +6645,7 @@ dependencies = [
"rand_chacha 0.3.1",
"serde",
"thiserror 2.0.12",
"tracing",
"wasm-bindgen",
]
@@ -7116,7 +7086,7 @@ dependencies = [
[[package]]
name = "nymvisor"
version = "0.1.17"
version = "0.1.18"
dependencies = [
"anyhow",
"bytes",
@@ -9261,9 +9231,9 @@ dependencies = [
[[package]]
name = "sphinx-packet"
version = "0.5.0"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b63a72efe7dce8a546d5cb855e60699ae69203d0d7e4335a654eb87e93d7d141"
checksum = "c26f0c20d909fdda1c5d0ece3973127ca421984d55b000215df365e93722fc6e"
dependencies = [
"aes",
"arrayref",
+6 -6
View File
@@ -39,7 +39,6 @@ members = [
"common/cosmwasm-smart-contracts/mixnet-contract",
"common/cosmwasm-smart-contracts/multisig-contract",
"common/cosmwasm-smart-contracts/vesting-contract",
"common/country-group",
"common/credential-storage",
"common/credential-utils",
"common/credential-verification",
@@ -97,9 +96,6 @@ members = [
"common/wireguard",
"common/wireguard-types",
"documentation/autodoc",
# "explorer-api",
# "explorer-api/explorer-api-requests",
# "explorer-api/explorer-client",
"gateway",
"integrations/bity",
"nym-api",
@@ -270,7 +266,6 @@ indicatif = "0.17.11"
inquire = "0.6.2"
ip_network = "0.4.1"
ipnetwork = "0.20"
isocountry = "0.3.2"
itertools = "0.14.0"
k256 = "0.13"
lazy_static = "1.5.0"
@@ -317,7 +312,7 @@ serde_with = "3.9.0"
serde_yaml = "0.9.25"
sha2 = "0.10.8"
si-scale = "0.2.3"
sphinx-packet = "=0.5.0"
sphinx-packet = "=0.6.0"
sqlx = "0.7.4"
strum = "0.26"
strum_macros = "0.26"
@@ -407,6 +402,11 @@ wasm-bindgen-futures = "0.4.49"
wasmtimer = "0.4.1"
web-sys = "0.3.76"
# for local development:
#[patch.crates-io]
#sphinx-packet = { path = "../sphinx" }
# Profile settings for individual crates
# Compile-time verified queries do quite a bit of work at compile time. Incremental
+2 -1
View File
@@ -168,8 +168,9 @@ generate-typescript:
cd tools/ts-rs-cli && cargo run && cd ../..
yarn types:lint:fix
# Run the integration tests for public nym-api endpoints
run-api-tests:
cd nym-api/tests/functional_test && yarn test:qa
dotenv -f envs/sandbox.env -- cargo test --test public-api-tests
# Build debian package, and update PPA
deb-cli: build-nym-cli
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-client"
version = "1.1.52"
version = "1.1.53"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
description = "Implementation of the Nym Client"
edition = "2021"
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-socks5-client"
version = "1.1.52"
version = "1.1.53"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
edition = "2021"
-1
View File
@@ -87,7 +87,6 @@ impl From<Init> for OverrideConfig {
use_anonymous_replies: init_config.use_reply_surbs,
fastmode: init_config.common_args.fastmode,
no_cover: init_config.common_args.no_cover,
geo_routing: None,
medium_toggle: false,
nyxd_urls: init_config.common_args.nyxd_urls,
enabled_credentials_mode: init_config.common_args.enabled_credentials_mode,
+1 -22
View File
@@ -16,8 +16,7 @@ use nym_bin_common::bin_info;
use nym_bin_common::completions::{fig_generate, ArgShell};
use nym_client_core::cli_helpers::CliClient;
use nym_client_core::client::base_client::storage::migration_helpers::v1_1_33;
use nym_client_core::client::topology_control::geo_aware_provider::CountryGroup;
use nym_client_core::config::{ForgetMe, GroupBy, TopologyStructure};
use nym_client_core::config::ForgetMe;
use nym_config::OptionalSet;
use nym_sphinx::addressing::Recipient;
use nym_sphinx::params::{PacketSize, PacketType};
@@ -107,7 +106,6 @@ pub(crate) struct OverrideConfig {
use_anonymous_replies: Option<bool>,
fastmode: bool,
no_cover: bool,
geo_routing: Option<CountryGroup>,
medium_toggle: bool,
nyxd_urls: Option<Vec<url::Url>>,
enabled_credentials_mode: Option<bool>,
@@ -138,21 +136,6 @@ pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
let secondary_packet_size = args.medium_toggle.then_some(PacketSize::ExtendedPacket16);
let no_per_hop_delays = args.medium_toggle;
let topology_structure = if args.medium_toggle {
// Use the location of the network-requester
let address = config
.core
.socks5
.provider_mix_address
.parse()
.expect("failed to parse provider mix address");
TopologyStructure::GeoAware(GroupBy::NymAddress(address))
} else if let Some(code) = args.geo_routing {
TopologyStructure::GeoAware(GroupBy::CountryGroup(code))
} else {
TopologyStructure::default()
};
let packet_type = if args.outfox {
PacketType::Outfox
} else {
@@ -176,10 +159,6 @@ pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
// NOTE: see comment above about the order of the other disble cover traffic config
.with_base(BaseClientConfig::with_disabled_cover_traffic, args.no_cover)
.with_base(BaseClientConfig::with_packet_type, packet_type)
.with_base(
BaseClientConfig::with_topology_structure,
topology_structure,
)
.with_base(BaseClientConfig::with_forget_me, args.forget_me)
.with_optional(Config::with_anonymous_replies, args.use_anonymous_replies)
.with_optional(Config::with_port, args.port)
-13
View File
@@ -6,7 +6,6 @@ use crate::commands::{override_config, OverrideConfig};
use clap::Args;
use nym_client_core::cli_helpers::client_run::CommonClientRunArgs;
use nym_client_core::client::base_client::storage::OnDiskPersistent;
use nym_client_core::client::topology_control::geo_aware_provider::CountryGroup;
use nym_socks5_client_core::NymClient;
use nym_sphinx::addressing::clients::Recipient;
use std::net::IpAddr;
@@ -37,10 +36,6 @@ pub(crate) struct Run {
#[clap(long)]
host: Option<IpAddr>,
/// Set geo-aware mixnode selection when sending mixnet traffic, for experiments only.
#[clap(long, hide = true, value_parser = validate_country_group, group="routing")]
geo_routing: Option<CountryGroup>,
/// Enable medium mixnet traffic, for experiments only.
/// This includes things like disabling cover traffic, no per hop delays, etc.
#[clap(long, hide = true)]
@@ -59,7 +54,6 @@ impl From<Run> for OverrideConfig {
use_anonymous_replies: run_config.use_anonymous_replies,
fastmode: run_config.common_args.fastmode,
no_cover: run_config.common_args.no_cover,
geo_routing: run_config.geo_routing,
medium_toggle: run_config.medium_toggle,
nyxd_urls: run_config.common_args.nyxd_urls,
enabled_credentials_mode: run_config.common_args.enabled_credentials_mode,
@@ -70,13 +64,6 @@ impl From<Run> for OverrideConfig {
}
}
fn validate_country_group(s: &str) -> Result<CountryGroup, String> {
match s.parse() {
Ok(cg) => Ok(cg),
Err(_) => Err(format!("failed to parse country group: {}", s)),
}
}
pub(crate) async fn execute(args: Run) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
eprintln!("Starting client {}...", args.common_args.id);
@@ -13,7 +13,7 @@ use std::{fmt, ops::Deref, str::FromStr};
#[cfg(feature = "verify")]
use hmac::{Hmac, Mac};
#[cfg(feature = "verify")]
use nym_crypto::asymmetric::encryption::{PrivateKey, PublicKey};
use nym_crypto::asymmetric::x25519::{PrivateKey, PublicKey};
#[cfg(feature = "verify")]
use sha2::Sha256;
@@ -190,15 +190,15 @@ impl<'de> Deserialize<'de> for ClientMac {
#[cfg(test)]
mod tests {
use super::*;
use nym_crypto::asymmetric::encryption;
use nym_crypto::asymmetric::x25519;
#[test]
#[cfg(feature = "verify")]
fn client_request_roundtrip() {
let mut rng = rand::thread_rng();
let gateway_key_pair = encryption::KeyPair::new(&mut rng);
let client_key_pair = encryption::KeyPair::new(&mut rng);
let gateway_key_pair = x25519::KeyPair::new(&mut rng);
let client_key_pair = x25519::KeyPair::new(&mut rng);
let nonce = 1234567890;
@@ -14,7 +14,7 @@ use std::{fmt, ops::Deref, str::FromStr};
#[cfg(feature = "verify")]
use hmac::{Hmac, Mac};
#[cfg(feature = "verify")]
use nym_crypto::asymmetric::encryption::{PrivateKey, PublicKey};
use nym_crypto::asymmetric::x25519::{PrivateKey, PublicKey};
#[cfg(feature = "verify")]
use sha2::Sha256;
@@ -199,15 +199,15 @@ impl<'de> Deserialize<'de> for ClientMac {
#[cfg(test)]
mod tests {
use super::*;
use nym_crypto::asymmetric::encryption;
use nym_crypto::asymmetric::x25519;
#[test]
#[cfg(feature = "verify")]
fn client_request_roundtrip() {
let mut rng = rand::thread_rng();
let gateway_key_pair = encryption::KeyPair::new(&mut rng);
let client_key_pair = encryption::KeyPair::new(&mut rng);
let gateway_key_pair = x25519::KeyPair::new(&mut rng);
let client_key_pair = x25519::KeyPair::new(&mut rng);
let nonce = 1234567890;
@@ -340,7 +340,7 @@ mod tests {
use std::{net::IpAddr, str::FromStr};
use nym_credentials_interface::CredentialSpendingData;
use nym_crypto::asymmetric::encryption::PrivateKey;
use nym_crypto::asymmetric::x25519::PrivateKey;
use nym_sphinx::addressing::Recipient;
use nym_wireguard_types::PeerPublicKey;
use x25519_dalek::PublicKey;
@@ -14,7 +14,7 @@ use std::{fmt, ops::Deref, str::FromStr};
#[cfg(feature = "verify")]
use hmac::{Hmac, Mac};
#[cfg(feature = "verify")]
use nym_crypto::asymmetric::encryption::{PrivateKey, PublicKey};
use nym_crypto::asymmetric::x25519::{PrivateKey, PublicKey};
#[cfg(feature = "verify")]
use sha2::Sha256;
@@ -199,15 +199,15 @@ impl<'de> Deserialize<'de> for ClientMac {
#[cfg(test)]
mod tests {
use super::*;
use nym_crypto::asymmetric::encryption;
use nym_crypto::asymmetric::x25519;
#[test]
#[cfg(feature = "verify")]
fn client_request_roundtrip() {
let mut rng = rand::thread_rng();
let gateway_key_pair = encryption::KeyPair::new(&mut rng);
let client_key_pair = encryption::KeyPair::new(&mut rng);
let gateway_key_pair = x25519::KeyPair::new(&mut rng);
let client_key_pair = x25519::KeyPair::new(&mut rng);
let nonce = 1234567890;
@@ -306,7 +306,7 @@ mod tests {
};
use nym_credentials_interface::CredentialSpendingData;
use nym_crypto::asymmetric::encryption::PrivateKey;
use nym_crypto::asymmetric::x25519::PrivateKey;
use nym_sphinx::addressing::Recipient;
use nym_wireguard_types::PeerPublicKey;
use x25519_dalek::PublicKey;
@@ -15,7 +15,7 @@ use std::{fmt, ops::Deref, str::FromStr};
#[cfg(feature = "verify")]
use hmac::{Hmac, Mac};
#[cfg(feature = "verify")]
use nym_crypto::asymmetric::encryption::{PrivateKey, PublicKey};
use nym_crypto::asymmetric::x25519::{PrivateKey, PublicKey};
#[cfg(feature = "verify")]
use sha2::Sha256;
@@ -251,7 +251,7 @@ impl<'de> Deserialize<'de> for ClientMac {
#[cfg(test)]
mod tests {
use super::*;
use nym_crypto::asymmetric::encryption;
use nym_crypto::asymmetric::x25519;
#[test]
fn create_ip_pair() {
@@ -266,8 +266,8 @@ mod tests {
fn client_request_roundtrip() {
let mut rng = rand::thread_rng();
let gateway_key_pair = encryption::KeyPair::new(&mut rng);
let client_key_pair = encryption::KeyPair::new(&mut rng);
let gateway_key_pair = x25519::KeyPair::new(&mut rng);
let client_key_pair = x25519::KeyPair::new(&mut rng);
let nonce = 1234567890;
@@ -230,7 +230,7 @@ mod tests {
};
use nym_credentials_interface::CredentialSpendingData;
use nym_crypto::asymmetric::encryption::PrivateKey;
use nym_crypto::asymmetric::x25519::PrivateKey;
use nym_sphinx::addressing::Recipient;
use nym_wireguard_types::PeerPublicKey;
use x25519_dalek::PublicKey;
@@ -15,7 +15,7 @@ use std::{fmt, ops::Deref, str::FromStr};
#[cfg(feature = "verify")]
use hmac::{Hmac, Mac};
#[cfg(feature = "verify")]
use nym_crypto::asymmetric::encryption::{PrivateKey, PublicKey};
use nym_crypto::asymmetric::x25519::{PrivateKey, PublicKey};
#[cfg(feature = "verify")]
use sha2::Sha256;
@@ -251,7 +251,7 @@ impl<'de> Deserialize<'de> for ClientMac {
#[cfg(test)]
mod tests {
use super::*;
use nym_crypto::asymmetric::encryption;
use nym_crypto::asymmetric::x25519;
#[test]
fn create_ip_pair() {
@@ -266,8 +266,8 @@ mod tests {
fn client_request_roundtrip() {
let mut rng = rand::thread_rng();
let gateway_key_pair = encryption::KeyPair::new(&mut rng);
let client_key_pair = encryption::KeyPair::new(&mut rng);
let gateway_key_pair = x25519::KeyPair::new(&mut rng);
let client_key_pair = x25519::KeyPair::new(&mut rng);
let nonce = 1234567890;
@@ -11,7 +11,7 @@ use nym_credentials::ecash::bandwidth::IssuanceTicketBook;
use nym_credentials::ecash::utils::obtain_aggregate_wallet;
use nym_credentials::IssuedTicketBook;
use nym_credentials_interface::TicketType;
use nym_crypto::asymmetric::identity;
use nym_crypto::asymmetric::ed25519;
use nym_ecash_time::{ecash_default_expiration_date, Date};
use nym_validator_client::coconut::all_ecash_api_clients;
use nym_validator_client::nym_api::EpochId;
@@ -31,7 +31,7 @@ where
C: EcashSigningClient + EcashQueryClient + Sync,
{
let mut rng = OsRng;
let signing_key = identity::PrivateKey::new(&mut rng);
let signing_key = ed25519::PrivateKey::new(&mut rng);
let expiration = expiration.unwrap_or_else(ecash_default_expiration_date);
let deposit_amount = client.get_required_deposit_amount().await?;
+2 -2
View File
@@ -4,8 +4,8 @@
use nym_credential_storage::error::StorageError;
use nym_credentials::error::Error as CredentialsError;
use nym_credentials_interface::CompactEcashError;
use nym_crypto::asymmetric::encryption::KeyRecoveryError;
use nym_crypto::asymmetric::identity::Ed25519RecoveryError;
use nym_crypto::asymmetric::ed25519::Ed25519RecoveryError;
use nym_crypto::asymmetric::x25519::KeyRecoveryError;
use nym_validator_client::coconut::EcashApiError;
use nym_validator_client::error::ValidatorClientError;
use thiserror::Error;
-4
View File
@@ -12,7 +12,6 @@ license.workspace = true
async-trait = { workspace = true }
base64 = { workspace = true }
bs58 = { workspace = true }
cfg-if = { workspace = true }
clap = { workspace = true, optional = true }
comfy-table = { workspace = true, optional = true }
futures = { workspace = true }
@@ -24,7 +23,6 @@ serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
sha2 = { workspace = true }
si-scale = { workspace = true }
tap = { workspace = true }
thiserror = { workspace = true }
url = { workspace = true, features = ["serde"] }
tokio = { workspace = true, features = ["macros"] }
@@ -35,9 +33,7 @@ zeroize = { workspace = true }
nym-id = { path = "../nym-id" }
nym-bandwidth-controller = { path = "../bandwidth-controller" }
nym-config = { path = "../config" }
nym-country-group = { path = "../country-group" }
nym-crypto = { path = "../crypto" }
nym-explorer-client = { path = "../../explorer-api/explorer-client" }
nym-gateway-client = { path = "../client-libs/gateway-client" }
nym-gateway-requests = { path = "../gateway-requests" }
nym-http-api-client = { path = "../http-api-client" }
@@ -14,7 +14,6 @@ url = { workspace = true, features = ["serde"] }
nym-config = { path = "../../config" }
nym-country-group = { path = "../../country-group" }
nym-pemstore = { path = "../../pemstore", optional = true }
# those are pulling so many deps T.T
+13 -39
View File
@@ -65,11 +65,10 @@ const DEFAULT_MAXIMUM_REPLY_KEY_AGE: Duration = Duration::from_secs(24 * 60 * 60
// stats reporting related
/// Time interval between reporting statistics to the given provider if it exist
/// Time interval between reporting statistics to the given provider if it exists
const STATS_REPORT_INTERVAL_SECS: Duration = Duration::from_secs(300);
use crate::error::InvalidTrafficModeFailure;
pub use nym_country_group::CountryGroup;
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
@@ -258,15 +257,6 @@ impl Config {
self
}
pub fn with_topology_structure(mut self, topology_structure: TopologyStructure) -> Self {
self.set_topology_structure(topology_structure);
self
}
pub fn set_topology_structure(&mut self, topology_structure: TopologyStructure) {
self.debug.topology.topology_structure = topology_structure;
}
pub fn with_no_per_hop_delays(mut self, no_per_hop_delays: bool) -> Self {
if no_per_hop_delays {
self.set_no_per_hop_delays()
@@ -415,6 +405,14 @@ pub struct Traffic {
/// Do not set it unless you understand the consequences of that change.
pub secondary_packet_size: Option<PacketSize>,
/// Specify whether any constructed sphinx packets should use the legacy format,
/// where the payload keys are explicitly attached rather than using the seeds
/// this affects any forward packets, acks and reply surbs
/// this flag should remain disabled until sufficient number of nodes on the network has upgraded
/// and support updated format.
/// in the case of reply surbs, the recipient must also understand the new encoding
pub use_legacy_sphinx_format: bool,
pub packet_type: PacketType,
}
@@ -442,6 +440,10 @@ impl Default for Traffic {
primary_packet_size: PacketSize::RegularPacket,
secondary_packet_size: None,
packet_type: PacketType::Mix,
// we should use the legacy format until sufficient number of nodes understand the
// improved encoding
use_legacy_sphinx_format: true,
}
}
}
@@ -546,9 +548,6 @@ pub struct Topology {
#[serde(with = "humantime_serde")]
pub max_startup_gateway_waiting_period: Duration,
/// Specifies the mixnode topology to be used for sending packets.
pub topology_structure: TopologyStructure,
/// Specifies a minimum performance of a mixnode that is used on route construction.
/// This setting is only applicable when `NymApi` topology is used.
pub minimum_mixnode_performance: u8,
@@ -570,30 +569,6 @@ pub struct Topology {
pub ignore_ingress_epoch_role: bool,
}
#[allow(clippy::large_enum_variant)]
#[derive(Default, Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum TopologyStructure {
#[default]
NymApi,
GeoAware(GroupBy),
}
#[allow(clippy::large_enum_variant)]
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum GroupBy {
CountryGroup(CountryGroup),
NymAddress(Recipient),
}
impl std::fmt::Display for GroupBy {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
GroupBy::CountryGroup(group) => write!(f, "group: {group}"),
GroupBy::NymAddress(address) => write!(f, "address: {address}"),
}
}
}
impl Default for Topology {
fn default() -> Self {
Topology {
@@ -601,7 +576,6 @@ impl Default for Topology {
topology_resolution_timeout: DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT,
disable_refreshing: false,
max_startup_gateway_waiting_period: DEFAULT_MAX_STARTUP_GATEWAY_WAITING_PERIOD,
topology_structure: TopologyStructure::default(),
minimum_mixnode_performance: DEFAULT_MIN_MIXNODE_PERFORMANCE,
minimum_gateway_performance: DEFAULT_MIN_GATEWAY_PERFORMANCE,
use_extended_topology: false,
+29 -14
View File
@@ -2,10 +2,9 @@
// SPDX-License-Identifier: Apache-2.0
use crate::old::v5::{
AcknowledgementsV5, ClientV5, ConfigV5, CoverTrafficV5, DebugConfigV5, GatewayConnectionV5,
GroupByV5, ReplySurbsV5, TopologyStructureV5, TopologyV5, TrafficV5,
AcknowledgementsV5, ClientV5, ConfigV5, CountryGroupV5, CoverTrafficV5, DebugConfigV5,
GatewayConnectionV5, GroupByV5, ReplySurbsV5, TopologyStructureV5, TopologyV5, TrafficV5,
};
use crate::CountryGroup;
use nym_sphinx_addressing::Recipient;
use nym_sphinx_params::{PacketSize, PacketType};
use serde::{Deserialize, Serialize};
@@ -369,31 +368,47 @@ impl From<TopologyStructureV4> for TopologyStructureV5 {
}
}
#[derive(Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize, Debug)]
pub enum CountryGroupV4 {
Europe,
NorthAmerica,
SouthAmerica,
Oceania,
Asia,
Africa,
Unknown,
}
impl From<CountryGroupV4> for CountryGroupV5 {
fn from(value: CountryGroupV4) -> Self {
match value {
CountryGroupV4::Europe => CountryGroupV5::Europe,
CountryGroupV4::NorthAmerica => CountryGroupV5::NorthAmerica,
CountryGroupV4::SouthAmerica => CountryGroupV5::SouthAmerica,
CountryGroupV4::Oceania => CountryGroupV5::Oceania,
CountryGroupV4::Asia => CountryGroupV5::Asia,
CountryGroupV4::Africa => CountryGroupV5::Africa,
CountryGroupV4::Unknown => CountryGroupV5::Unknown,
}
}
}
#[allow(clippy::large_enum_variant)]
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum GroupByV4 {
CountryGroup(CountryGroup),
CountryGroup(CountryGroupV4),
NymAddress(Recipient),
}
impl From<GroupByV4> for GroupByV5 {
fn from(value: GroupByV4) -> Self {
match value {
GroupByV4::CountryGroup(country) => GroupByV5::CountryGroup(country),
GroupByV4::CountryGroup(country) => GroupByV5::CountryGroup(country.into()),
GroupByV4::NymAddress(addr) => GroupByV5::NymAddress(addr),
}
}
}
impl std::fmt::Display for GroupByV4 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
GroupByV4::CountryGroup(group) => write!(f, "group: {}", group),
GroupByV4::NymAddress(address) => write!(f, "address: {}", address),
}
}
}
impl Default for TopologyV4 {
fn default() -> Self {
TopologyV4 {
+12 -29
View File
@@ -2,8 +2,8 @@
// SPDX-License-Identifier: Apache-2.0
use crate::{
Acknowledgements, Client, Config, CountryGroup, CoverTraffic, DebugConfig, GatewayConnection,
GroupBy, ReplySurbs, Topology, TopologyStructure, Traffic,
Acknowledgements, Client, Config, CoverTraffic, DebugConfig, GatewayConnection, ReplySurbs,
Topology, Traffic,
};
use nym_sphinx_addressing::Recipient;
use nym_sphinx_params::{PacketSize, PacketType};
@@ -146,7 +146,6 @@ impl From<ConfigV5> for Config {
.debug
.topology
.max_startup_gateway_waiting_period,
topology_structure: value.debug.topology.topology_structure.into(),
..Default::default()
},
reply_surbs: ReplySurbs {
@@ -372,40 +371,24 @@ pub enum TopologyStructureV5 {
GeoAware(GroupByV5),
}
impl From<TopologyStructureV5> for TopologyStructure {
fn from(value: TopologyStructureV5) -> Self {
match value {
TopologyStructureV5::NymApi => TopologyStructure::NymApi,
TopologyStructureV5::GeoAware(group_by) => TopologyStructure::GeoAware(group_by.into()),
}
}
#[derive(Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize, Debug)]
pub enum CountryGroupV5 {
Europe,
NorthAmerica,
SouthAmerica,
Oceania,
Asia,
Africa,
Unknown,
}
#[allow(clippy::large_enum_variant)]
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum GroupByV5 {
CountryGroup(CountryGroup),
CountryGroup(CountryGroupV5),
NymAddress(Recipient),
}
impl From<GroupByV5> for GroupBy {
fn from(value: GroupByV5) -> Self {
match value {
GroupByV5::CountryGroup(country) => GroupBy::CountryGroup(country),
GroupByV5::NymAddress(addr) => GroupBy::NymAddress(addr),
}
}
}
impl std::fmt::Display for GroupByV5 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
GroupByV5::CountryGroup(group) => write!(f, "group: {}", group),
GroupByV5::NymAddress(address) => write!(f, "address: {}", address),
}
}
}
impl Default for TopologyV5 {
fn default() -> Self {
TopologyV5 {
@@ -1,7 +1,7 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_crypto::asymmetric::identity::Ed25519RecoveryError;
use nym_crypto::asymmetric::ed25519::Ed25519RecoveryError;
use nym_gateway_requests::shared_key::SharedKeyConversionError;
use thiserror::Error;
@@ -5,7 +5,7 @@
#![warn(clippy::unwrap_used)]
use async_trait::async_trait;
use nym_crypto::asymmetric::identity;
use nym_crypto::asymmetric::ed25519;
use nym_gateway_requests::SharedSymmetricKey;
use std::error::Error;
@@ -36,9 +36,7 @@ pub trait GatewaysDetailsStore {
async fn all_gateways(&self) -> Result<Vec<GatewayRegistration>, Self::StorageError>;
/// Return identity keys of all registered gateways.
async fn all_gateways_identities(
&self,
) -> Result<Vec<identity::PublicKey>, Self::StorageError> {
async fn all_gateways_identities(&self) -> Result<Vec<ed25519::PublicKey>, Self::StorageError> {
Ok(self
.all_gateways()
.await?
@@ -64,7 +62,7 @@ pub trait GatewaysDetailsStore {
async fn upgrade_stored_remote_gateway_key(
&self,
gateway_id: identity::PublicKey,
gateway_id: ed25519::PublicKey,
updated_key: &SharedSymmetricKey,
) -> Result<(), Self::StorageError>;
@@ -3,7 +3,7 @@
use crate::BadGateway;
use cosmrs::AccountId;
use nym_crypto::asymmetric::identity;
use nym_crypto::asymmetric::ed25519;
use nym_gateway_requests::shared_key::{LegacySharedKeys, SharedGatewayKey, SharedSymmetricKey};
use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter};
@@ -29,7 +29,7 @@ pub struct GatewayRegistration {
}
impl GatewayRegistration {
pub fn gateway_id(&self) -> identity::PublicKey {
pub fn gateway_id(&self) -> ed25519::PublicKey {
self.details.gateway_id()
}
}
@@ -64,7 +64,7 @@ impl From<GatewayDetails> for GatewayRegistration {
impl GatewayDetails {
pub fn new_remote(
gateway_id: identity::PublicKey,
gateway_id: ed25519::PublicKey,
shared_key: Arc<SharedGatewayKey>,
gateway_owner_address: Option<AccountId>,
gateway_listener: Url,
@@ -77,11 +77,11 @@ impl GatewayDetails {
})
}
pub fn new_custom(gateway_id: identity::PublicKey, data: Option<Vec<u8>>) -> Self {
pub fn new_custom(gateway_id: ed25519::PublicKey, data: Option<Vec<u8>>) -> Self {
GatewayDetails::Custom(CustomGatewayDetails { gateway_id, data })
}
pub fn gateway_id(&self) -> identity::PublicKey {
pub fn gateway_id(&self) -> ed25519::PublicKey {
match self {
GatewayDetails::Remote(details) => details.gateway_id,
GatewayDetails::Custom(details) => details.gateway_id,
@@ -157,7 +157,7 @@ pub struct RawRegisteredGateway {
#[derive(Debug, Clone, Copy)]
pub struct RegisteredGateway {
pub gateway_id: identity::PublicKey,
pub gateway_id: ed25519::PublicKey,
pub registration_timestamp: OffsetDateTime,
@@ -179,7 +179,7 @@ impl TryFrom<RawRemoteGatewayDetails> for RemoteGatewayDetails {
fn try_from(value: RawRemoteGatewayDetails) -> Result<Self, Self::Error> {
let gateway_id =
identity::PublicKey::from_base58_string(&value.gateway_id_bs58).map_err(|source| {
ed25519::PublicKey::from_base58_string(&value.gateway_id_bs58).map_err(|source| {
BadGateway::MalformedGatewayIdentity {
gateway_id: value.gateway_id_bs58.clone(),
source,
@@ -267,7 +267,7 @@ impl<'a> From<&'a RemoteGatewayDetails> for RawRemoteGatewayDetails {
#[derive(Debug, Clone)]
pub struct RemoteGatewayDetails {
pub gateway_id: identity::PublicKey,
pub gateway_id: ed25519::PublicKey,
pub shared_key: Arc<SharedGatewayKey>,
@@ -288,7 +288,7 @@ impl TryFrom<RawCustomGatewayDetails> for CustomGatewayDetails {
fn try_from(value: RawCustomGatewayDetails) -> Result<Self, Self::Error> {
let gateway_id =
identity::PublicKey::from_base58_string(&value.gateway_id_bs58).map_err(|source| {
ed25519::PublicKey::from_base58_string(&value.gateway_id_bs58).map_err(|source| {
BadGateway::MalformedGatewayIdentity {
gateway_id: value.gateway_id_bs58.clone(),
source,
@@ -314,12 +314,12 @@ impl<'a> From<&'a CustomGatewayDetails> for RawCustomGatewayDetails {
#[derive(Debug, Clone)]
pub struct CustomGatewayDetails {
pub gateway_id: identity::PublicKey,
pub gateway_id: ed25519::PublicKey,
pub data: Option<Vec<u8>>,
}
impl CustomGatewayDetails {
pub fn new(gateway_id: identity::PublicKey) -> CustomGatewayDetails {
pub fn new(gateway_id: ed25519::PublicKey) -> CustomGatewayDetails {
Self {
gateway_id,
data: None,
@@ -14,7 +14,7 @@ use crate::{
};
use log::info;
use nym_client_core_gateways_storage::GatewayDetails;
use nym_crypto::asymmetric::identity;
use nym_crypto::asymmetric::ed25519;
use nym_topology::NymTopology;
use nym_validator_client::UserAgent;
use std::path::PathBuf;
@@ -29,7 +29,7 @@ pub struct CommonClientAddGatewayArgs {
/// Explicitly specify id of the gateway to register with.
/// If unspecified, a random gateway will be chosen instead.
#[cfg_attr(feature = "cli", clap(long, alias = "gateway"))]
pub gateway_id: Option<identity::PublicKey>,
pub gateway_id: Option<ed25519::PublicKey>,
/// Specifies whether the client will attempt to enforce tls connection to the desired gateway.
#[cfg_attr(feature = "cli", clap(long))]
@@ -14,7 +14,7 @@ use crate::{
};
use log::info;
use nym_client_core_gateways_storage::GatewayDetails;
use nym_crypto::asymmetric::identity;
use nym_crypto::asymmetric::ed25519;
use nym_sphinx::addressing::Recipient;
use nym_topology::NymTopology;
use nym_validator_client::UserAgent;
@@ -42,7 +42,7 @@ pub struct CommonClientInitArgs {
/// Id of the gateway we are going to connect to.
#[cfg_attr(feature = "cli", clap(long))]
pub gateway: Option<identity::PublicKey>,
pub gateway: Option<ed25519::PublicKey>,
/// Specifies whether the client will attempt to enforce tls connection to the desired gateway.
#[cfg_attr(feature = "cli", clap(long))]
@@ -1,7 +1,7 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_crypto::asymmetric::identity;
use nym_crypto::asymmetric::ed25519;
use nym_sphinx::addressing::Recipient;
use std::path::PathBuf;
@@ -15,7 +15,7 @@ pub struct CommonClientRunArgs {
/// Id of the gateway we want to connect to. If overridden, it is user's responsibility to
/// ensure prior registration happened
#[cfg_attr(feature = "cli", clap(long))]
pub gateway: Option<identity::PublicKey>,
pub gateway: Option<ed25519::PublicKey>,
/// Comma separated list of rest endpoints of the nyxd validators
#[cfg_attr(
@@ -4,7 +4,7 @@
use crate::cli_helpers::{CliClient, CliClientConfig};
use crate::client::base_client::non_wasm_helpers::setup_fs_gateways_storage;
use crate::client::base_client::storage::helpers::set_active_gateway;
use nym_crypto::asymmetric::identity;
use nym_crypto::asymmetric::ed25519;
#[cfg_attr(feature = "cli", derive(clap::Args))]
#[derive(Debug, Clone)]
@@ -15,7 +15,7 @@ pub struct CommonClientSwitchGatewaysArgs {
/// Id of the gateway we want to switch to.
#[cfg_attr(feature = "cli", clap(long))]
pub gateway_id: identity::PublicKey,
pub gateway_id: ed25519::PublicKey,
}
pub async fn switch_gateway<C, A>(args: A) -> Result<(), C::Error>
+2 -2
View File
@@ -1,7 +1,7 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_crypto::asymmetric::identity;
use nym_crypto::asymmetric::ed25519;
use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter};
use time::OffsetDateTime;
@@ -10,7 +10,7 @@ use url::Url;
#[derive(Serialize, Deserialize)]
pub struct GatewayInfo {
pub registration: OffsetDateTime,
pub identity: identity::PublicKey,
pub identity: ed25519::PublicKey,
pub active: bool,
pub typ: String,
@@ -39,7 +39,7 @@ use nym_bandwidth_controller::BandwidthController;
use nym_client_core_config_types::ForgetMe;
use nym_client_core_gateways_storage::{GatewayDetails, GatewaysDetailsStore};
use nym_credential_storage::storage::Storage as CredentialStorage;
use nym_crypto::asymmetric::{encryption, identity};
use nym_crypto::asymmetric::{ed25519, x25519};
use nym_crypto::hkdf::DerivationMaterial;
use nym_gateway_client::client::config::GatewayClientConfig;
use nym_gateway_client::{
@@ -367,7 +367,7 @@ where
// buffer controlling all messages fetched from provider
// required so that other components would be able to use them (say the websocket)
fn start_received_messages_buffer_controller(
local_encryption_keypair: Arc<encryption::KeyPair>,
local_encryption_keypair: Arc<x25519::KeyPair>,
query_receiver: ReceivedBufferRequestReceiver,
mixnet_receiver: MixnetMessageReceiver,
reply_key_storage: SentReplyKeys,
@@ -552,18 +552,12 @@ where
user_agent: Option<UserAgent>,
) -> Box<dyn TopologyProvider + Send + Sync> {
// if no custom provider was ... provided ..., create one using nym-api
custom_provider.unwrap_or_else(|| match config_topology.topology_structure {
config::TopologyStructure::NymApi => Box::new(NymApiTopologyProvider::new(
custom_provider.unwrap_or_else(|| {
Box::new(NymApiTopologyProvider::new(
config_topology,
nym_api_urls,
user_agent,
)),
config::TopologyStructure::GeoAware(group_by) => {
warn!("using deprecated 'GeoAware' topology provider - this option will be removed very soon");
#[allow(deprecated)]
Box::new(crate::client::topology_control::GeoAwareTopologyProvider::new(nym_api_urls, group_by))
}
))
})
}
@@ -942,7 +936,7 @@ where
pub struct BaseClient {
pub address: Recipient,
pub identity_keys: Arc<identity::KeyPair>,
pub identity_keys: Arc<ed25519::KeyPair>,
pub client_input: ClientInputStatus,
pub client_output: ClientOutputStatus,
pub client_state: ClientState,
@@ -5,7 +5,7 @@ use crate::client::key_manager::persistence::KeyStore;
use crate::client::key_manager::ClientKeys;
use crate::error::ClientCoreError;
use nym_client_core_gateways_storage::{ActiveGateway, GatewayRegistration, GatewaysDetailsStore};
use nym_crypto::asymmetric::identity;
use nym_crypto::asymmetric::ed25519;
// helpers for error wrapping
pub async fn set_active_gateway<D>(
@@ -26,7 +26,7 @@ where
pub async fn get_active_gateway_identity<D>(
details_store: &D,
) -> Result<Option<identity::PublicKey>, ClientCoreError>
) -> Result<Option<ed25519::PublicKey>, ClientCoreError>
where
D: GatewaysDetailsStore,
D::StorageError: Send + Sync + 'static,
@@ -42,7 +42,7 @@ where
pub async fn get_all_registered_identities<D>(
details_store: &D,
) -> Result<Vec<identity::PublicKey>, ClientCoreError>
) -> Result<Vec<ed25519::PublicKey>, ClientCoreError>
where
D: GatewaysDetailsStore + Sync,
D::StorageError: Send + Sync + 'static,
@@ -62,6 +62,10 @@ where
/// Optional secondary predefined packet size used for the loop cover messages.
secondary_packet_size: Option<PacketSize>,
/// Specify whether any constructed packets should use the legacy format,
/// where the payload keys are explicitly attached rather than using the seeds
use_legacy_sphinx_format: bool,
packet_type: PacketType,
stats_tx: ClientStatsSender,
@@ -130,6 +134,7 @@ impl LoopCoverTrafficStream<OsRng> {
topology_access,
primary_packet_size: traffic_config.primary_packet_size,
secondary_packet_size: traffic_config.secondary_packet_size,
use_legacy_sphinx_format: traffic_config.use_legacy_sphinx_format,
packet_type: traffic_config.packet_type,
stats_tx,
task_client,
@@ -182,6 +187,7 @@ impl LoopCoverTrafficStream<OsRng> {
let cover_message = match generate_loop_cover_packet(
&mut self.rng,
self.use_legacy_sphinx_format,
topology_ref,
&self.ack_key,
&self.our_full_destination,
@@ -3,7 +3,7 @@
use crate::client::key_manager::persistence::KeyStore;
use nym_crypto::{
asymmetric::{encryption, identity},
asymmetric::{ed25519, x25519},
hkdf::{DerivationMaterial, InvalidLength},
};
use nym_gateway_requests::shared_key::{LegacySharedKeys, SharedGatewayKey, SharedSymmetricKey};
@@ -25,10 +25,10 @@ mod test;
#[derive(Clone)]
pub struct ClientKeys {
/// identity key associated with the client instance.
identity_keypair: Arc<identity::KeyPair>,
identity_keypair: Arc<ed25519::KeyPair>,
/// encryption key associated with the client instance.
encryption_keypair: Arc<encryption::KeyPair>,
encryption_keypair: Arc<x25519::KeyPair>,
/// key used for producing and processing acknowledgement packets.
ack_key: Arc<AckKey>,
@@ -41,8 +41,8 @@ impl ClientKeys {
R: RngCore + CryptoRng,
{
ClientKeys {
identity_keypair: Arc::new(identity::KeyPair::new(rng)),
encryption_keypair: Arc::new(encryption::KeyPair::new(rng)),
identity_keypair: Arc::new(ed25519::KeyPair::new(rng)),
encryption_keypair: Arc::new(x25519::KeyPair::new(rng)),
ack_key: Arc::new(AckKey::new(rng)),
}
}
@@ -56,18 +56,18 @@ impl ClientKeys {
{
let secret = derivation_material.derive_secret()?;
Ok(ClientKeys {
identity_keypair: Arc::new(identity::KeyPair::from_secret(
identity_keypair: Arc::new(ed25519::KeyPair::from_secret(
secret,
derivation_material.index(),
)),
encryption_keypair: Arc::new(encryption::KeyPair::new(rng)),
encryption_keypair: Arc::new(x25519::KeyPair::new(rng)),
ack_key: Arc::new(AckKey::new(rng)),
})
}
pub fn from_keys(
id_keypair: identity::KeyPair,
enc_keypair: encryption::KeyPair,
id_keypair: ed25519::KeyPair,
enc_keypair: x25519::KeyPair,
ack_key: AckKey,
) -> Self {
Self {
@@ -85,13 +85,13 @@ impl ClientKeys {
store.store_keys(self).await
}
/// Gets an atomically reference counted pointer to [`identity::KeyPair`].
pub fn identity_keypair(&self) -> Arc<identity::KeyPair> {
/// Gets an atomically reference counted pointer to [`ed25519::KeyPair`].
pub fn identity_keypair(&self) -> Arc<ed25519::KeyPair> {
Arc::clone(&self.identity_keypair)
}
/// Gets an atomically reference counted pointer to [`encryption::KeyPair`].
pub fn encryption_keypair(&self) -> Arc<encryption::KeyPair> {
/// Gets an atomically reference counted pointer to [`x25519::KeyPair`].
pub fn encryption_keypair(&self) -> Arc<x25519::KeyPair> {
Arc::clone(&self.encryption_keypair)
}
/// Gets an atomically reference counted pointer to [`AckKey`].
@@ -103,8 +103,8 @@ impl ClientKeys {
fn _assert_keys_zeroize_on_drop() {
fn _assert_zeroize_on_drop<T: ZeroizeOnDrop>() {}
_assert_zeroize_on_drop::<identity::KeyPair>();
_assert_zeroize_on_drop::<encryption::KeyPair>();
_assert_zeroize_on_drop::<ed25519::KeyPair>();
_assert_zeroize_on_drop::<x25519::KeyPair>();
_assert_zeroize_on_drop::<AckKey>();
_assert_zeroize_on_drop::<LegacySharedKeys>();
_assert_zeroize_on_drop::<SharedSymmetricKey>();
@@ -11,7 +11,7 @@ use tokio::sync::Mutex;
#[cfg(not(target_arch = "wasm32"))]
use crate::config::disk_persistence::ClientKeysPaths;
#[cfg(not(target_arch = "wasm32"))]
use nym_crypto::asymmetric::{encryption, identity};
use nym_crypto::asymmetric::{ed25519, x25519};
#[cfg(not(target_arch = "wasm32"))]
use nym_pemstore::traits::{PemStorableKey, PemStorableKeyPair};
#[cfg(not(target_arch = "wasm32"))]
@@ -86,13 +86,13 @@ impl OnDiskKeys {
}
#[doc(hidden)]
pub fn load_encryption_keypair(&self) -> Result<encryption::KeyPair, OnDiskKeysError> {
pub fn load_encryption_keypair(&self) -> Result<x25519::KeyPair, OnDiskKeysError> {
let encryption_paths = self.paths.encryption_key_pair_path();
self.load_keypair(encryption_paths, "encryption")
}
#[doc(hidden)]
pub fn load_identity_keypair(&self) -> Result<identity::KeyPair, OnDiskKeysError> {
pub fn load_identity_keypair(&self) -> Result<ed25519::KeyPair, OnDiskKeysError> {
let identity_paths = self.paths.identity_key_pair_path();
self.load_keypair(identity_paths, "identity")
}
@@ -4,7 +4,7 @@
use async_trait::async_trait;
use log::{debug, error};
use nym_credential_storage::storage::Storage as CredentialStorage;
use nym_crypto::asymmetric::identity;
use nym_crypto::asymmetric::ed25519;
use nym_gateway_client::error::GatewayClientError;
use nym_gateway_client::GatewayClient;
pub use nym_gateway_client::{GatewayPacketRouter, PacketRouter};
@@ -30,7 +30,7 @@ fn erase_err<E: std::error::Error + Send + Sync + 'static>(err: E) -> ErasedGate
/// This combines combines the functionalities of being able to send and receive mix packets.
#[async_trait]
pub trait GatewayTransceiver: GatewaySender + GatewayReceiver {
fn gateway_identity(&self) -> identity::PublicKey;
fn gateway_identity(&self) -> ed25519::PublicKey;
fn ws_fd(&self) -> Option<RawFd>;
async fn send_client_request(
&mut self,
@@ -75,7 +75,7 @@ pub trait GatewayReceiver {
#[async_trait]
impl<G: GatewayTransceiver + ?Sized + Send> GatewayTransceiver for Box<G> {
#[inline]
fn gateway_identity(&self) -> identity::PublicKey {
fn gateway_identity(&self) -> ed25519::PublicKey {
(**self).gateway_identity()
}
fn ws_fd(&self) -> Option<RawFd> {
@@ -134,7 +134,7 @@ where
St: CredentialStorage,
<St as CredentialStorage>::StorageError: Send + Sync + 'static,
{
fn gateway_identity(&self) -> identity::PublicKey {
fn gateway_identity(&self) -> ed25519::PublicKey {
self.gateway_client.gateway_identity()
}
fn ws_fd(&self) -> Option<RawFd> {
@@ -190,7 +190,7 @@ pub enum LocalGatewayError {
#[cfg(not(target_arch = "wasm32"))]
pub struct LocalGateway {
/// Identity of the locally managed gateway
local_identity: identity::PublicKey,
local_identity: ed25519::PublicKey,
// 'sender' part
/// Channel responsible for taking mix packets and forwarding them further into the further mixnet layers.
@@ -203,7 +203,7 @@ pub struct LocalGateway {
#[cfg(not(target_arch = "wasm32"))]
impl LocalGateway {
pub fn new(
local_identity: identity::PublicKey,
local_identity: ed25519::PublicKey,
packet_forwarder: nym_mixnet_client::forwarder::MixForwardingSender,
packet_router_tx: oneshot::Sender<PacketRouter>,
) -> Self {
@@ -221,7 +221,7 @@ mod nonwasm_sealed {
#[async_trait]
impl GatewayTransceiver for LocalGateway {
fn gateway_identity(&self) -> identity::PublicKey {
fn gateway_identity(&self) -> ed25519::PublicKey {
self.local_identity
}
fn ws_fd(&self) -> Option<RawFd> {
@@ -263,7 +263,7 @@ mod nonwasm_sealed {
// if we ever decided to start writing unit tests... : )
pub struct MockGateway {
dummy_identity: identity::PublicKey,
dummy_identity: ed25519::PublicKey,
packet_router: Option<PacketRouter>,
sent: Vec<MixPacket>,
}
@@ -303,7 +303,7 @@ impl GatewaySender for MockGateway {
#[async_trait]
impl GatewayTransceiver for MockGateway {
fn gateway_identity(&self) -> identity::PublicKey {
fn gateway_identity(&self) -> ed25519::PublicKey {
self.dummy_identity
}
fn ws_fd(&self) -> Option<RawFd> {
@@ -109,6 +109,10 @@ pub(crate) struct Config {
/// Optional secondary predefined packet size used for the encapsulated messages.
secondary_packet_size: Option<PacketSize>,
/// Specify whether any constructed reply surbs should use the legacy format,
/// where the payload keys are explicitly attached rather than using the seeds
use_legacy_sphinx_format: bool,
}
impl Config {
@@ -118,6 +122,7 @@ impl Config {
average_packet_delay: Duration,
average_ack_delay: Duration,
deterministic_route_selection: bool,
use_legacy_reply_surb_format: bool,
) -> Self {
Config {
ack_key,
@@ -127,6 +132,7 @@ impl Config {
average_ack_delay,
primary_packet_size: PacketSize::default(),
secondary_packet_size: None,
use_legacy_sphinx_format: use_legacy_reply_surb_format,
}
}
@@ -186,6 +192,7 @@ where
config.sender_address,
config.average_packet_delay,
config.average_ack_delay,
config.use_legacy_sphinx_format,
);
MessageHandler {
config,
@@ -254,9 +261,11 @@ where
let topology_permit = self.topology_access.get_read_permit().await;
let topology = self.get_topology(&topology_permit)?;
let reply_surbs = self
.message_preparer
.generate_reply_surbs(amount, topology)?;
let reply_surbs = self.message_preparer.generate_reply_surbs(
self.config.use_legacy_sphinx_format,
amount,
topology,
)?;
let reply_keys = reply_surbs
.iter()
@@ -522,6 +531,7 @@ where
self.generate_reply_surbs_with_keys(amount as usize).await?;
let message = NymMessage::new_repliable(RepliableMessage::new_additional_surbs(
self.config.use_legacy_sphinx_format,
sender_tag,
reply_surbs,
));
@@ -559,8 +569,12 @@ where
.generate_reply_surbs_with_keys(num_reply_surbs as usize)
.await?;
let message =
NymMessage::new_repliable(RepliableMessage::new_data(message, sender_tag, reply_surbs));
let message = NymMessage::new_repliable(RepliableMessage::new_data(
self.config.use_legacy_sphinx_format,
message,
sender_tag,
reply_surbs,
));
self.try_split_and_send_non_reply_message(
message,
@@ -99,6 +99,7 @@ impl<'a> From<&'a Config> for message_handler::Config {
cfg.traffic.average_packet_delay,
cfg.acks.average_ack_delay,
cfg.traffic.deterministic_route_selection,
cfg.traffic.use_legacy_sphinx_format,
)
.with_custom_primary_packet_size(cfg.traffic.primary_packet_size)
.with_custom_secondary_packet_size(cfg.traffic.secondary_packet_size)
@@ -252,6 +252,7 @@ where
(
generate_loop_cover_packet(
&mut self.rng,
self.config.traffic.use_legacy_sphinx_format,
topology_ref,
&self.config.ack_key,
&self.config.our_full_destination,
@@ -9,7 +9,7 @@ use futures::channel::mpsc;
use futures::lock::Mutex;
use futures::StreamExt;
use log::*;
use nym_crypto::asymmetric::encryption;
use nym_crypto::asymmetric::x25519;
use nym_crypto::Digest;
use nym_gateway_client::MixnetMessageReceiver;
use nym_sphinx::anonymous_replies::requests::{
@@ -39,7 +39,7 @@ pub type ReconstructedMessagesReceiver = mpsc::UnboundedReceiver<Vec<Reconstruct
struct ReceivedMessagesBufferInner<R: MessageReceiver> {
messages: Vec<ReconstructedMessage>,
local_encryption_keypair: Arc<encryption::KeyPair>,
local_encryption_keypair: Arc<x25519::KeyPair>,
// TODO: looking how it 'looks' here, perhaps `MessageReceiver` should be renamed to something
// else instead.
@@ -176,7 +176,7 @@ struct ReceivedMessagesBuffer<R: MessageReceiver> {
impl<R: MessageReceiver> ReceivedMessagesBuffer<R> {
fn new(
local_encryption_keypair: Arc<encryption::KeyPair>,
local_encryption_keypair: Arc<x25519::KeyPair>,
reply_key_storage: SentReplyKeys,
reply_controller_sender: ReplyControllerSender,
stats_tx: ClientStatsSender,
@@ -250,10 +250,10 @@ impl<R: MessageReceiver> ReceivedMessagesBuffer<R> {
let mut reconstructed = Vec::new();
for msg in msgs {
let (reply_surbs, from_surb_request) = match msg.content {
RepliableMessageContent::Data {
message,
reply_surbs,
} => {
RepliableMessageContent::Data(content) => {
let reply_surbs = content.reply_surbs;
let message = content.message;
trace!(
"received message that also contained additional {} reply surbs from {:?}!",
reply_surbs.len(),
@@ -264,7 +264,9 @@ impl<R: MessageReceiver> ReceivedMessagesBuffer<R> {
(reply_surbs, false)
}
RepliableMessageContent::AdditionalSurbs { reply_surbs } => {
RepliableMessageContent::AdditionalSurbs(content) => {
let reply_surbs = content.reply_surbs;
trace!(
"received additional {} reply surbs from {:?}!",
reply_surbs.len(),
@@ -272,9 +274,37 @@ impl<R: MessageReceiver> ReceivedMessagesBuffer<R> {
);
(reply_surbs, true)
}
RepliableMessageContent::Heartbeat {
additional_reply_surbs,
} => {
RepliableMessageContent::Heartbeat(content) => {
let additional_reply_surbs = content.additional_reply_surbs;
error!("received a repliable heartbeat message - we don't know how to handle it yet (and we won't know until future PRs)");
(additional_reply_surbs, false)
}
RepliableMessageContent::DataV2(content) => {
let reply_surbs = content.reply_surbs;
let message = content.message;
trace!(
"received message that also contained additional {} reply surbs from {:?}!",
reply_surbs.len(),
msg.sender_tag
);
reconstructed.push(ReconstructedMessage::new(message, msg.sender_tag));
(reply_surbs, false)
}
RepliableMessageContent::AdditionalSurbsV2(content) => {
let reply_surbs = content.reply_surbs;
trace!(
"received additional {} reply surbs from {:?}!",
reply_surbs.len(),
msg.sender_tag
);
(reply_surbs, true)
}
RepliableMessageContent::HeartbeatV2(content) => {
let additional_reply_surbs = content.additional_reply_surbs;
error!("received a repliable heartbeat message - we don't know how to handle it yet (and we won't know until future PRs)");
(additional_reply_surbs, false)
}
@@ -536,7 +566,7 @@ pub(crate) struct ReceivedMessagesBufferController<R: MessageReceiver> {
impl<R: MessageReceiver + Clone + Send + 'static> ReceivedMessagesBufferController<R> {
pub(crate) fn new(
local_encryption_keypair: Arc<encryption::KeyPair>,
local_encryption_keypair: Arc<x25519::KeyPair>,
query_receiver: ReceivedBufferRequestReceiver,
mixnet_packet_receiver: MixnetMessageReceiver,
reply_key_storage: SentReplyKeys,
@@ -1,214 +0,0 @@
use crate::config::GroupBy;
use log::{debug, error};
use nym_explorer_client::{ExplorerClient, PrettyDetailedMixNodeBond};
use nym_network_defaults::var_names::EXPLORER_API;
use nym_topology::{
provider_trait::{async_trait, TopologyProvider},
NymTopology,
};
use nym_validator_client::client::NodeId;
use rand::{prelude::SliceRandom, thread_rng};
use std::collections::HashMap;
use tap::TapOptional;
use url::Url;
pub use nym_country_group::CountryGroup;
fn create_explorer_client() -> Option<ExplorerClient> {
let Ok(explorer_api_url) = std::env::var(EXPLORER_API) else {
error!("Missing EXPLORER_API");
return None;
};
let Ok(explorer_api_url) = explorer_api_url.parse() else {
error!("Failed to parse EXPLORER_API");
return None;
};
log::debug!("Using explorer-api url: {}", explorer_api_url);
let Ok(client) = nym_explorer_client::ExplorerClient::new(explorer_api_url) else {
error!("Failed to create explorer-api client");
return None;
};
Some(client)
}
fn group_mixnodes_by_country_code(
mixnodes: Vec<PrettyDetailedMixNodeBond>,
) -> HashMap<CountryGroup, Vec<NodeId>> {
mixnodes
.into_iter()
.fold(HashMap::<CountryGroup, Vec<NodeId>>::new(), |mut acc, m| {
if let Some(ref location) = m.location {
let country_code = location.two_letter_iso_country_code.clone();
let group_code = CountryGroup::new(country_code.as_str());
let mixnodes = acc.entry(group_code).or_default();
mixnodes.push(m.mix_id);
}
acc
})
}
fn log_mixnode_distribution(mixnodes: &HashMap<CountryGroup, Vec<NodeId>>) {
let mixnode_distribution = mixnodes
.iter()
.map(|(k, v)| format!("{}: {}", k, v.len()))
.collect::<Vec<_>>()
.join(", ");
debug!("Mixnode distribution - {}", mixnode_distribution);
}
fn check_layer_integrity(topology: NymTopology) -> Result<(), ()> {
if topology.ensure_minimally_routable().is_err() {
error!("Layer is missing in topology!");
return Err(());
}
Ok(())
}
#[deprecated(note = "use NymApiTopologyProvider instead as explorer API will soon be removed")]
pub struct GeoAwareTopologyProvider {
validator_client: nym_validator_client::client::NymApiClient,
filter_on: GroupBy,
}
#[allow(deprecated)]
impl GeoAwareTopologyProvider {
pub fn new(mut nym_api_urls: Vec<Url>, filter_on: GroupBy) -> GeoAwareTopologyProvider {
log::info!(
"Creating geo-aware topology provider with filter on {}",
filter_on
);
nym_api_urls.shuffle(&mut thread_rng());
GeoAwareTopologyProvider {
validator_client: nym_validator_client::client::NymApiClient::new(
nym_api_urls[0].clone(),
),
filter_on,
}
}
async fn get_topology(&self) -> Option<NymTopology> {
let rewarded_set = self
.validator_client
.get_current_rewarded_set()
.await
.inspect_err(|err| error!("failed to get current rewarded set: {err}"))
.ok()?;
let mut topology = NymTopology::new_empty(rewarded_set);
let mixnodes = match self
.validator_client
.get_all_basic_active_mixing_assigned_nodes()
.await
{
Err(err) => {
error!("failed to get network mixnodes - {err}");
return None;
}
Ok(mixes) => mixes,
};
let gateways = match self
.validator_client
.get_all_basic_entry_assigned_nodes()
.await
{
Err(err) => {
error!("failed to get network gateways - {err}");
return None;
}
Ok(gateways) => gateways,
};
// Also fetch mixnodes cached by explorer-api, with the purpose of getting their
// geolocation.
debug!("Fetching mixnodes from explorer-api...");
let explorer_client = create_explorer_client()?;
let Ok(mixnodes_from_explorer_api) = explorer_client.get_mixnodes().await else {
error!("failed to get mixnodes from explorer-api");
return None;
};
debug!("Fetching gateways from explorer-api...");
let Ok(gateways_from_explorer_api) = explorer_client.get_gateways().await else {
error!("failed to get mixnodes from explorer-api");
return None;
};
// Determine what we should filter around
let filter_on = match self.filter_on {
GroupBy::CountryGroup(group) => group,
GroupBy::NymAddress(recipient) => {
// Convert recipient into a country group by extracting out the gateway part and
// using that as the country code.
let gateway = recipient.gateway().to_base58_string();
// Lookup the location of this gateway by using the location data from the
// explorer-api
let gateway_location = gateways_from_explorer_api
.iter()
.find(|g| g.gateway.identity_key == gateway)
.and_then(|g| g.location.clone())
.map(|location| location.two_letter_iso_country_code)
.tap_none(|| error!("No location found for the gateway: {}", gateway))?;
debug!(
"Filtering on nym-address: {}, with location: {}",
recipient, gateway_location
);
CountryGroup::new(&gateway_location)
}
};
debug!("Filter group: {}", filter_on);
// Partition mixnodes_from_explorer_api according to the value of
// two_letter_iso_country_code.
// NOTE: we construct the full distribution here, but only use the one we're interested in.
// The reason we this instead of a straight filter is that this opens up the possibility to
// complement a small grouping with mixnodes from adjecent countries.
let mixnode_distribution = group_mixnodes_by_country_code(mixnodes_from_explorer_api);
log_mixnode_distribution(&mixnode_distribution);
let Some(filtered_mixnode_ids) = mixnode_distribution.get(&filter_on) else {
error!("no mixnodes found for: {}", filter_on);
return None;
};
let mixnodes = mixnodes
.into_iter()
.filter(|m| filtered_mixnode_ids.contains(&m.node_id))
.collect::<Vec<_>>();
topology.add_skimmed_nodes(&mixnodes);
topology.add_skimmed_nodes(&gateways);
// TODO: return real error type
check_layer_integrity(topology.clone()).ok()?;
Some(topology)
}
}
#[allow(deprecated)]
#[cfg(not(target_arch = "wasm32"))]
#[async_trait]
impl TopologyProvider for GeoAwareTopologyProvider {
// this will be manually refreshed on a timer specified inside mixnet client config
async fn get_new_topology(&mut self) -> Option<NymTopology> {
self.get_topology().await
}
}
#[allow(deprecated)]
#[cfg(target_arch = "wasm32")]
#[async_trait(?Send)]
impl TopologyProvider for GeoAwareTopologyProvider {
// this will be manually refreshed on a timer specified inside mixnet client config
async fn get_new_topology(&mut self) -> Option<NymTopology> {
self.get_topology().await
}
}
@@ -17,11 +17,8 @@ use tokio::time::sleep;
use wasmtimer::tokio::sleep;
mod accessor;
pub mod geo_aware_provider;
pub mod nym_api_provider;
#[allow(deprecated)]
pub use geo_aware_provider::GeoAwareTopologyProvider;
pub use nym_api_provider::{Config as NymApiTopologyProviderConfig, NymApiTopologyProvider};
pub use nym_topology::provider_trait::TopologyProvider;
+1 -1
View File
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
use crate::client::mix_traffic::transceiver::ErasedGatewayError;
use nym_crypto::asymmetric::identity::Ed25519RecoveryError;
use nym_crypto::asymmetric::ed25519::Ed25519RecoveryError;
use nym_gateway_client::error::GatewayClientError;
use nym_topology::node::RoutingNodeError;
use nym_topology::{NodeId, NymTopologyError};
+6 -6
View File
@@ -5,7 +5,7 @@ use crate::error::ClientCoreError;
use crate::init::types::RegistrationResult;
use futures::{SinkExt, StreamExt};
use log::{debug, info, trace, warn};
use nym_crypto::asymmetric::identity;
use nym_crypto::asymmetric::ed25519;
use nym_gateway_client::GatewayClient;
use nym_topology::node::RoutingNode;
use nym_validator_client::client::IdentityKeyRef;
@@ -52,7 +52,7 @@ const PING_TIMEOUT: Duration = Duration::from_millis(1000);
// The abstraction that some of these helpers use
pub trait ConnectableGateway {
fn node_id(&self) -> NodeId;
fn identity(&self) -> identity::PublicKey;
fn identity(&self) -> ed25519::PublicKey;
fn clients_address(&self, prefer_ipv6: bool) -> Option<String>;
fn is_wss(&self) -> bool;
}
@@ -62,7 +62,7 @@ impl ConnectableGateway for RoutingNode {
self.node_id
}
fn identity(&self) -> identity::PublicKey {
fn identity(&self) -> ed25519::PublicKey {
self.identity_key
}
@@ -287,7 +287,7 @@ pub(super) fn get_specified_gateway(
must_use_tls: bool,
) -> Result<RoutingNode, ClientCoreError> {
log::debug!("Requesting specified gateway: {}", gateway_identity);
let user_gateway = identity::PublicKey::from_base58_string(gateway_identity)
let user_gateway = ed25519::PublicKey::from_base58_string(gateway_identity)
.map_err(ClientCoreError::UnableToCreatePublicKeyFromGatewayId)?;
let gateway = gateways
@@ -312,9 +312,9 @@ pub(super) fn get_specified_gateway(
}
pub(super) async fn register_with_gateway(
gateway_id: identity::PublicKey,
gateway_id: ed25519::PublicKey,
gateway_listener: Url,
our_identity: Arc<identity::KeyPair>,
our_identity: Arc<ed25519::KeyPair>,
#[cfg(unix)] connection_fd_callback: Option<Arc<dyn Fn(RawFd) + Send + Sync>>,
) -> Result<RegistrationResult, ClientCoreError> {
let mut gateway_client = GatewayClient::new_init(
+7 -7
View File
@@ -9,7 +9,7 @@ use crate::init::{setup_gateway, use_loaded_gateway_details};
use nym_client_core_gateways_storage::{
GatewayRegistration, GatewaysDetailsStore, RemoteGatewayDetails,
};
use nym_crypto::asymmetric::identity;
use nym_crypto::asymmetric::ed25519;
use nym_gateway_client::client::InitGatewayClient;
use nym_gateway_requests::shared_key::SharedGatewayKey;
use nym_sphinx::addressing::clients::Recipient;
@@ -26,14 +26,14 @@ use url::Url;
pub enum SelectedGateway {
Remote {
gateway_id: identity::PublicKey,
gateway_id: ed25519::PublicKey,
gateway_owner_address: Option<AccountId>,
gateway_listener: Url,
},
Custom {
gateway_id: identity::PublicKey,
gateway_id: ed25519::PublicKey,
additional_data: Option<Vec<u8>>,
},
}
@@ -77,7 +77,7 @@ impl SelectedGateway {
gateway_id: String,
additional_data: Option<Vec<u8>>,
) -> Result<Self, ClientCoreError> {
let gateway_id = identity::PublicKey::from_base58_string(&gateway_id)
let gateway_id = ed25519::PublicKey::from_base58_string(&gateway_id)
.map_err(|source| ClientCoreError::MalformedGatewayIdentity { gateway_id, source })?;
Ok(SelectedGateway::Custom {
@@ -86,7 +86,7 @@ impl SelectedGateway {
})
}
pub fn gateway_id(&self) -> &identity::PublicKey {
pub fn gateway_id(&self) -> &ed25519::PublicKey {
match self {
SelectedGateway::Remote { gateway_id, .. } => gateway_id,
SelectedGateway::Custom { gateway_id, .. } => gateway_id,
@@ -142,7 +142,7 @@ impl InitialisationResult {
)
}
pub fn gateway_id(&self) -> identity::PublicKey {
pub fn gateway_id(&self) -> ed25519::PublicKey {
self.gateway_registration.details.gateway_id()
}
}
@@ -271,7 +271,7 @@ impl GatewaySetup {
}
/// new gateway setup performed by each client that's inbuilt in a gateway (like NR or IPR)
pub fn new_inbuilt(identity: identity::PublicKey) -> Self {
pub fn new_inbuilt(identity: ed25519::PublicKey) -> Self {
GatewaySetup::New {
specification: GatewaySelectionSpecification::Custom {
gateway_identity: identity.to_base58_string(),
@@ -17,7 +17,7 @@ use nym_credential_storage::ephemeral_storage::EphemeralStorage as EphemeralCred
use nym_credential_storage::storage::Storage as CredentialStorage;
use nym_credentials::CredentialSpendingData;
use nym_credentials_interface::TicketType;
use nym_crypto::asymmetric::identity;
use nym_crypto::asymmetric::ed25519;
use nym_gateway_requests::registration::handshake::client_handshake;
use nym_gateway_requests::{
BinaryRequest, ClientControlRequest, ClientRequest, GatewayProtocolVersionExt,
@@ -57,7 +57,7 @@ pub(crate) mod websockets;
use websockets::connect_async;
pub struct GatewayConfig {
pub gateway_identity: identity::PublicKey,
pub gateway_identity: ed25519::PublicKey,
// currently a dead field
pub gateway_owner: Option<String>,
@@ -67,7 +67,7 @@ pub struct GatewayConfig {
impl GatewayConfig {
pub fn new(
gateway_identity: identity::PublicKey,
gateway_identity: ed25519::PublicKey,
gateway_owner: Option<String>,
gateway_listener: String,
) -> Self {
@@ -93,8 +93,8 @@ pub struct GatewayClient<C, St = EphemeralCredentialStorage> {
authenticated: bool,
bandwidth: ClientBandwidth,
gateway_address: String,
gateway_identity: identity::PublicKey,
local_identity: Arc<identity::KeyPair>,
gateway_identity: ed25519::PublicKey,
local_identity: Arc<ed25519::KeyPair>,
shared_key: Option<Arc<SharedGatewayKey>>,
connection: SocketState,
packet_router: PacketRouter,
@@ -117,7 +117,7 @@ impl<C, St> GatewayClient<C, St> {
pub fn new(
cfg: GatewayClientConfig,
gateway_config: GatewayConfig,
local_identity: Arc<identity::KeyPair>,
local_identity: Arc<ed25519::KeyPair>,
// TODO: make it mandatory. if you don't want to pass it, use `new_init`
shared_key: Option<Arc<SharedGatewayKey>>,
packet_router: PacketRouter,
@@ -145,7 +145,7 @@ impl<C, St> GatewayClient<C, St> {
}
}
pub fn gateway_identity(&self) -> identity::PublicKey {
pub fn gateway_identity(&self) -> ed25519::PublicKey {
self.gateway_identity
}
@@ -1063,8 +1063,8 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
// for initialisation we do not need credential storage. Though it's still a bit weird we have to set the generic...
pub fn new_init(
gateway_listener: Url,
gateway_identity: identity::PublicKey,
local_identity: Arc<identity::KeyPair>,
gateway_identity: ed25519::PublicKey,
local_identity: Arc<ed25519::KeyPair>,
#[cfg(unix)] connection_fd_callback: Option<Arc<dyn Fn(RawFd) + Send + Sync>>,
) -> Self {
log::trace!("Initialising gateway client");
@@ -15,7 +15,7 @@ use nym_credentials::{
AggregatedCoinIndicesSignatures, AggregatedExpirationDateSignatures, EpochVerificationKey,
};
use nym_credentials_interface::TicketType;
use nym_crypto::asymmetric::identity;
use nym_crypto::asymmetric::ed25519;
use std::fs;
use std::path::PathBuf;
use tempfile::NamedTempFile;
@@ -83,7 +83,7 @@ async fn issue_client_ticketbook(
);
let persistent_storage = initialise_persistent_storage(credentials_store).await;
let private_id_key: identity::PrivateKey = nym_pemstore::load_key(private_id_key)?;
let private_id_key: ed25519::PrivateKey = nym_pemstore::load_key(private_id_key)?;
utils::issue_credential(
&client,
&persistent_storage,
@@ -1,6 +1,6 @@
use clap::{Args, Parser, Subcommand};
use nym_bin_common::output_format::OutputFormat;
use nym_crypto::asymmetric::identity;
use nym_crypto::asymmetric::ed25519;
use nym_types::helpers::ConsoleSigningOutput;
use nym_validator_client::nyxd::error::NyxdError;
use std::path::PathBuf;
@@ -34,14 +34,14 @@ pub struct SignArgs {
pub async fn sign(args: SignArgs) -> Result<(), NyxdError> {
eprintln!(">>> loading: {}", args.private_key.display());
let private_identity_key: identity::PrivateKey =
let private_identity_key: ed25519::PrivateKey =
nym_pemstore::load_key(args.private_key).expect("failed to load key");
print_signed_msg(&private_identity_key, &args.base58_msg, args.output);
Ok(())
}
fn print_signed_msg(private_key: &identity::PrivateKey, raw_msg: &str, output: OutputFormat) {
fn print_signed_msg(private_key: &ed25519::PrivateKey, raw_msg: &str, output: OutputFormat) {
let trimmed = raw_msg.trim();
eprintln!(">>> attempting to sign: {trimmed}");
-15
View File
@@ -1,15 +0,0 @@
[package]
name = "nym-country-group"
version = "0.1.0"
authors.workspace = true
repository.workspace = true
homepage.workspace = true
documentation.workspace = true
edition.workspace = true
license.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
serde = { workspace = true, features = ["derive"] }
tracing.workspace = true
-158
View File
@@ -1,158 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use serde::{Deserialize, Serialize};
use std::fmt;
use tracing::info;
#[derive(Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize, Debug)]
pub enum CountryGroup {
Europe,
NorthAmerica,
SouthAmerica,
Oceania,
Asia,
Africa,
Unknown,
}
impl CountryGroup {
// We map country codes into group, which initially are continent codes to a first approximation,
// but we do it manually to reserve the right to tweak this distribution for our purposes.
// NOTE: I did this quickly, and it's not a complete list of all countries, but only those that
// were present in the network at the time. Please add more as needed.
pub fn new(country_code: &str) -> Self {
let country_code = country_code.to_uppercase();
use CountryGroup::*;
match country_code.as_ref() {
// Europe
"AT" => Europe,
"BG" => Europe,
"CH" => Europe,
"CY" => Europe,
"CZ" => Europe,
"DE" => Europe,
"DK" => Europe,
"ES" => Europe,
"FI" => Europe,
"FR" => Europe,
"GB" => Europe,
"GR" => Europe,
"IE" => Europe,
"IT" => Europe,
"LT" => Europe,
"LU" => Europe,
"LV" => Europe,
"MD" => Europe,
"MT" => Europe,
"NL" => Europe,
"NO" => Europe,
"PL" => Europe,
"RO" => Europe,
"SE" => Europe,
"SK" => Europe,
"TR" => Europe,
"UA" => Europe,
// North America
"CA" => NorthAmerica,
"MX" => NorthAmerica,
"US" => NorthAmerica,
// South America
"AR" => SouthAmerica,
"BR" => SouthAmerica,
"CL" => SouthAmerica,
"CO" => SouthAmerica,
"CR" => SouthAmerica,
"GT" => SouthAmerica,
// Oceania
"AU" => Oceania,
// Asia
"AM" => Asia,
"BH" => Asia,
"CN" => Asia,
"GE" => Asia,
"HK" => Asia,
"ID" => Asia,
"IL" => Asia,
"IN" => Asia,
"JP" => Asia,
"KH" => Asia,
"KR" => Asia,
"KZ" => Asia,
"MY" => Asia,
"RU" => Asia,
"SG" => Asia,
"TH" => Asia,
"VN" => Asia,
// Africa
"SC" => Africa,
"UG" => Africa,
"ZA" => Africa,
// And group level codes work too
"EU" => Europe,
"NA" => NorthAmerica,
"SA" => SouthAmerica,
"OC" => Oceania,
"AS" => Asia,
"AF" => Africa,
// And some aliases
"EUROPE" => Europe,
"NORTHAMERICA" => NorthAmerica,
"SOUTHAMERICA" => SouthAmerica,
"OCEANIA" => Oceania,
"ASIA" => Asia,
"AFRICA" => Africa,
_ => {
info!("Unknown country code: {country_code}");
Unknown
}
}
}
}
impl fmt::Display for CountryGroup {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use CountryGroup::*;
match self {
Europe => write!(f, "EU"),
NorthAmerica => write!(f, "NA"),
SouthAmerica => write!(f, "SA"),
Oceania => write!(f, "OC"),
Asia => write!(f, "AS"),
Africa => write!(f, "AF"),
Unknown => write!(f, "Unknown"),
}
}
}
impl std::str::FromStr for CountryGroup {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
let group = CountryGroup::new(s);
if group == CountryGroup::Unknown {
Err(())
} else {
Ok(group)
}
}
}
impl CountryGroup {
#[allow(unused)]
fn known(self) -> Option<CountryGroup> {
use CountryGroup::*;
match self {
Europe | NorthAmerica | SouthAmerica | Oceania | Asia | Africa => Some(self),
Unknown => None,
}
}
}
@@ -172,6 +172,21 @@ impl MemoryEcachTicketbookManager {
);
}
pub(crate) async fn contains_ticketbook(&self, ticketbook: &IssuedTicketBook) -> bool {
let ser = ticketbook.pack();
let search_data = Zeroizing::new(ser.data);
self.inner
.read()
.await
.ticketbooks
.iter()
.any(|ticketbook| {
let ser = ticketbook.1.ticketbook.pack();
let data = Zeroizing::new(ser.data);
search_data.eq(&data)
})
}
pub(crate) async fn get_ticketbooks_info(&self) -> Vec<BasicTicketbookInformation> {
let guard = self.inner.read().await;
@@ -95,6 +95,24 @@ impl SqliteEcashTicketbookManager {
Ok(())
}
pub(crate) async fn contains_ticketbook_data(&self, data: &[u8]) -> Result<bool, sqlx::Error> {
let exists = sqlx::query(
r#"
SELECT EXISTS (
SELECT 1
FROM ecash_ticketbook
WHERE ticketbook_data = ?
)
"#,
)
.bind(data)
.fetch_optional(&self.connection_pool)
.await?
.is_some();
Ok(exists)
}
pub(crate) async fn get_ticketbooks_info(
&self,
) -> Result<Vec<BasicTicketbookInformation>, sqlx::Error> {
@@ -70,6 +70,13 @@ impl Storage for EphemeralStorage {
Ok(())
}
async fn contains_issued_ticketbook(
&self,
ticketbook: &IssuedTicketBook,
) -> Result<bool, StorageError> {
Ok(self.storage_manager.contains_ticketbook(ticketbook).await)
}
async fn get_ticketbooks_info(
&self,
) -> Result<Vec<BasicTicketbookInformation>, Self::StorageError> {
@@ -145,6 +145,16 @@ impl Storage for PersistentStorage {
Ok(())
}
async fn contains_issued_ticketbook(
&self,
ticketbook: &IssuedTicketBook,
) -> Result<bool, Self::StorageError> {
let ser = ticketbook.pack();
let data = Zeroizing::new(ser.data);
Ok(self.storage_manager.contains_ticketbook_data(&data).await?)
}
async fn get_ticketbooks_info(
&self,
) -> Result<Vec<BasicTicketbookInformation>, Self::StorageError> {
+5
View File
@@ -37,6 +37,11 @@ pub trait Storage: Clone + Send + Sync {
ticketbook: &IssuedTicketBook,
) -> Result<(), Self::StorageError>;
async fn contains_issued_ticketbook(
&self,
ticketbook: &IssuedTicketBook,
) -> Result<bool, Self::StorageError>;
async fn get_ticketbooks_info(
&self,
) -> Result<Vec<BasicTicketbookInformation>, Self::StorageError>;
@@ -12,7 +12,7 @@ use nym_credentials_interface::{
BlindedSignature, KeyPairUser, PartialWallet, TicketType, VerificationKeyAuth,
WalletSignatures, WithdrawalRequest,
};
use nym_crypto::asymmetric::identity;
use nym_crypto::asymmetric::ed25519;
use nym_ecash_contract_common::deposit::DepositId;
use nym_ecash_time::{ecash_default_expiration_date, ecash_today, EcashTime};
use nym_validator_client::nym_api::EpochId;
@@ -27,7 +27,7 @@ pub struct IssuanceTicketBook {
deposit_id: DepositId,
/// base58 encoded private key ensuring the depositer requested these attributes
signing_key: identity::PrivateKey,
signing_key: ed25519::PrivateKey,
/// ecash keypair related to the credential
ecash_keypair: KeyPairUser,
@@ -43,7 +43,7 @@ impl IssuanceTicketBook {
pub fn new<M: AsRef<[u8]>>(
deposit_id: DepositId,
identifier: M,
signing_key: identity::PrivateKey,
signing_key: ed25519::PrivateKey,
ticketbook_type: TicketType,
) -> Self {
//this expiration date will get fed to the ecash library, force midnight to be set
@@ -59,7 +59,7 @@ impl IssuanceTicketBook {
pub fn new_with_expiration<M: AsRef<[u8]>>(
deposit_id: DepositId,
identifier: M,
signing_key: identity::PrivateKey,
signing_key: ed25519::PrivateKey,
ticketbook_type: TicketType,
expiration_date: Date,
) -> Self {
@@ -93,7 +93,7 @@ impl IssuanceTicketBook {
message
}
fn request_signature(&self, signing_request: &CredentialSigningData) -> identity::Signature {
fn request_signature(&self, signing_request: &CredentialSigningData) -> ed25519::Signature {
let message = Self::request_plaintext(&signing_request.withdrawal_request, self.deposit_id);
self.signing_key.sign(message)
}
@@ -127,7 +127,7 @@ impl IssuanceTicketBook {
self.deposit_id
}
pub fn identity_key(&self) -> &identity::PrivateKey {
pub fn identity_key(&self) -> &ed25519::PrivateKey {
&self.signing_key
}
+1 -1
View File
@@ -3,7 +3,7 @@
use crate::ecash::bandwidth::issued::CURRENT_SERIALIZATION_REVISION;
use nym_credentials_interface::CompactEcashError;
use nym_crypto::asymmetric::encryption::KeyRecoveryError;
use nym_crypto::asymmetric::x25519::KeyRecoveryError;
use nym_validator_client::ValidatorClientError;
use thiserror::Error;
@@ -18,7 +18,7 @@ pub mod bs58_ed25519_pubkey {
}
pub mod bs58_ed25519_signature {
use crate::asymmetric::identity::Signature;
use crate::asymmetric::ed25519::Signature;
use serde::{Deserialize, Deserializer, Serializer};
pub fn serialize<S: Serializer>(
+9 -4
View File
@@ -1,8 +1,13 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod encryption;
pub mod identity;
pub mod ed25519;
pub mod x25519;
pub use encryption as x25519;
pub use identity as ed25519;
// don't break existing imports
// but deprecate them
#[deprecated(note = "use ed25519 instead")]
pub use ed25519 as identity;
#[deprecated(note = "use x25519 instead")]
pub use x25519 as encryption;
+6 -6
View File
@@ -1,7 +1,7 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::asymmetric::encryption;
use crate::asymmetric::x25519;
use crate::hkdf;
use cipher::{Key, KeyIvInit, StreamCipher};
use digest::crypto_common::BlockSizeUser;
@@ -15,14 +15,14 @@ use rand::{CryptoRng, RngCore};
#[cfg(feature = "rand")]
pub fn new_ephemeral_shared_key<C, D, R>(
rng: &mut R,
remote_key: &encryption::PublicKey,
) -> (encryption::KeyPair, Key<C>)
remote_key: &x25519::PublicKey,
) -> (x25519::KeyPair, Key<C>)
where
C: StreamCipher + KeyIvInit,
D: Digest + BlockSizeUser + Clone,
R: RngCore + CryptoRng,
{
let ephemeral_keypair = encryption::KeyPair::new(rng);
let ephemeral_keypair = x25519::KeyPair::new(rng);
// after performing diffie-hellman we don't care about the private component anymore
let dh_result = ephemeral_keypair.private_key().diffie_hellman(remote_key);
@@ -43,8 +43,8 @@ where
/// Recompute shared key using remote public key and local private key.
pub fn recompute_shared_key<C, D>(
remote_key: &encryption::PublicKey,
local_key: &encryption::PrivateKey,
remote_key: &x25519::PublicKey,
local_key: &x25519::PrivateKey,
) -> Key<C>
where
C: StreamCipher + KeyIvInit,
@@ -6,7 +6,7 @@ use crate::registration::handshake::state::State;
use crate::SharedGatewayKey;
use futures::future::BoxFuture;
use futures::{Sink, Stream};
use nym_crypto::asymmetric::identity;
use nym_crypto::asymmetric::ed25519;
use rand::{CryptoRng, RngCore};
use std::future::Future;
use std::pin::Pin;
@@ -48,8 +48,8 @@ impl Future for GatewayHandshake<'_> {
pub fn client_handshake<'a, S, R>(
rng: &'a mut R,
ws_stream: &'a mut S,
identity: &'a identity::KeyPair,
gateway_pubkey: identity::PublicKey,
identity: &'a ed25519::KeyPair,
gateway_pubkey: ed25519::PublicKey,
expects_credential_usage: bool,
derive_aes256_gcm_siv_key: bool,
#[cfg(not(target_arch = "wasm32"))] shutdown: TaskClient,
@@ -78,7 +78,7 @@ where
pub fn gateway_handshake<'a, S, R>(
rng: &'a mut R,
ws_stream: &'a mut S,
identity: &'a identity::KeyPair,
identity: &'a ed25519::KeyPair,
received_init_payload: Vec<u8>,
shutdown: TaskClient,
) -> GatewayHandshake<'a>
@@ -14,11 +14,7 @@ use crate::{
use futures::{Sink, SinkExt, Stream, StreamExt};
use nym_crypto::asymmetric::{ed25519, x25519};
use nym_crypto::symmetric::aead::random_nonce;
use nym_crypto::{
asymmetric::{encryption, identity},
generic_array::typenum::Unsigned,
hkdf,
};
use nym_crypto::{generic_array::typenum::Unsigned, hkdf};
use nym_sphinx::params::{GatewayEncryptionAlgorithm, GatewaySharedKeyHkdfAlgorithm};
use rand::{thread_rng, CryptoRng, RngCore};
use std::any::{type_name, Any};
@@ -74,14 +70,14 @@ impl<'a, S, R> State<'a, S, R> {
pub(crate) fn new(
rng: &'a mut R,
ws_stream: &'a mut S,
identity: &'a identity::KeyPair,
remote_pubkey: Option<identity::PublicKey>,
identity: &'a ed25519::KeyPair,
remote_pubkey: Option<ed25519::PublicKey>,
#[cfg(not(target_arch = "wasm32"))] shutdown: TaskClient,
) -> Self
where
R: CryptoRng + RngCore,
{
let ephemeral_keypair = encryption::KeyPair::new(rng);
let ephemeral_keypair = x25519::KeyPair::new(rng);
State {
ws_stream,
rng,
@@ -113,7 +109,7 @@ impl<'a, S, R> State<'a, S, R> {
}
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn local_ephemeral_key(&self) -> &encryption::PublicKey {
pub(crate) fn local_ephemeral_key(&self) -> &x25519::PublicKey {
self.ephemeral_keypair.public_key()
}
@@ -150,7 +146,7 @@ impl<'a, S, R> State<'a, S, R> {
pub(crate) fn derive_shared_key(
&mut self,
remote_ephemeral_key: &encryption::PublicKey,
remote_ephemeral_key: &x25519::PublicKey,
initiator_salt: Option<&[u8]>,
) {
let dh_result = self
@@ -189,7 +185,7 @@ impl<'a, S, R> State<'a, S, R> {
// assuming x is local and y is remote
pub(crate) fn prepare_key_material_sig(
&self,
remote_ephemeral_key: &encryption::PublicKey,
remote_ephemeral_key: &x25519::PublicKey,
) -> Result<MaterialExchange, HandshakeError> {
let plaintext: Vec<_> = self
.ephemeral_keypair
@@ -243,7 +239,7 @@ impl<'a, S, R> State<'a, S, R> {
)?;
// now verify signature itself
let signature = identity::Signature::from_bytes(&decrypted_signature)
let signature = ed25519::Signature::from_bytes(&decrypted_signature)
.map_err(|_| HandshakeError::InvalidSignature)?;
// g^y || g^x, if y is remote and x is local
@@ -261,7 +257,7 @@ impl<'a, S, R> State<'a, S, R> {
}
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn update_remote_identity(&mut self, remote_pubkey: identity::PublicKey) {
pub(crate) fn update_remote_identity(&mut self, remote_pubkey: ed25519::PublicKey) {
self.remote_pubkey = Some(remote_pubkey)
}
+11 -11
View File
@@ -1,6 +1,6 @@
use std::fmt;
use nym_crypto::asymmetric::identity;
use nym_crypto::asymmetric::ed25519;
use nym_sphinx::addressing::clients::Recipient;
use serde::{Deserialize, Serialize};
use time::OffsetDateTime;
@@ -200,7 +200,7 @@ impl fmt::Display for IpPacketRequestData {
}
impl IpPacketRequestData {
pub fn add_signature(&mut self, signature: identity::Signature) -> Option<identity::Signature> {
pub fn add_signature(&mut self, signature: ed25519::Signature) -> Option<ed25519::Signature> {
match self {
IpPacketRequestData::StaticConnect(request) => {
request.signature = Some(signature);
@@ -269,11 +269,11 @@ impl StaticConnectRequest {
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct SignedStaticConnectRequest {
pub request: StaticConnectRequest,
pub signature: Option<identity::Signature>,
pub signature: Option<ed25519::Signature>,
}
impl SignedRequest for SignedStaticConnectRequest {
fn identity(&self) -> Option<&identity::PublicKey> {
fn identity(&self) -> Option<&ed25519::PublicKey> {
Some(self.request.reply_to.identity())
}
@@ -286,7 +286,7 @@ impl SignedRequest for SignedStaticConnectRequest {
})
}
fn signature(&self) -> Option<&identity::Signature> {
fn signature(&self) -> Option<&ed25519::Signature> {
self.signature.as_ref()
}
@@ -333,11 +333,11 @@ impl DynamicConnectRequest {
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct SignedDynamicConnectRequest {
pub request: DynamicConnectRequest,
pub signature: Option<identity::Signature>,
pub signature: Option<ed25519::Signature>,
}
impl SignedRequest for SignedDynamicConnectRequest {
fn identity(&self) -> Option<&identity::PublicKey> {
fn identity(&self) -> Option<&ed25519::PublicKey> {
Some(self.request.reply_to.identity())
}
@@ -350,7 +350,7 @@ impl SignedRequest for SignedDynamicConnectRequest {
})
}
fn signature(&self) -> Option<&identity::Signature> {
fn signature(&self) -> Option<&ed25519::Signature> {
self.signature.as_ref()
}
@@ -382,11 +382,11 @@ impl DisconnectRequest {
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct SignedDisconnectRequest {
pub request: DisconnectRequest,
pub signature: Option<identity::Signature>,
pub signature: Option<ed25519::Signature>,
}
impl SignedRequest for SignedDisconnectRequest {
fn identity(&self) -> Option<&identity::PublicKey> {
fn identity(&self) -> Option<&ed25519::PublicKey> {
Some(self.request.reply_to.identity())
}
@@ -399,7 +399,7 @@ impl SignedRequest for SignedDisconnectRequest {
})
}
fn signature(&self) -> Option<&identity::Signature> {
fn signature(&self) -> Option<&ed25519::Signature> {
self.signature.as_ref()
}
+4 -4
View File
@@ -3,7 +3,7 @@
use crate::error::NetworkTestingError;
use crate::TestMessage;
use nym_crypto::asymmetric::encryption;
use nym_crypto::asymmetric::x25519;
use nym_sphinx::acknowledgements::identifier::recover_identifier;
use nym_sphinx::acknowledgements::AckKey;
use nym_sphinx::chunking::fragment::FragmentIdentifier;
@@ -31,7 +31,7 @@ impl<T> From<FragmentIdentifier> for Received<T> {
}
pub struct TestPacketProcessor<T, R: MessageReceiver = SphinxMessageReceiver> {
local_encryption_keypair: Arc<encryption::KeyPair>,
local_encryption_keypair: Arc<x25519::KeyPair>,
ack_key: Arc<AckKey>,
/// Structure responsible for decrypting and recovering plaintext message from received ciphertexts.
@@ -42,7 +42,7 @@ pub struct TestPacketProcessor<T, R: MessageReceiver = SphinxMessageReceiver> {
impl<T> TestPacketProcessor<T, SphinxMessageReceiver> {
pub fn new_sphinx_processor(
local_encryption_keypair: Arc<encryption::KeyPair>,
local_encryption_keypair: Arc<x25519::KeyPair>,
ack_key: Arc<AckKey>,
) -> Self {
Self::new(local_encryption_keypair, ack_key)
@@ -53,7 +53,7 @@ impl<T, R> TestPacketProcessor<T, R>
where
R: MessageReceiver,
{
pub fn new(local_encryption_keypair: Arc<encryption::KeyPair>, ack_key: Arc<AckKey>) -> Self {
pub fn new(local_encryption_keypair: Arc<x25519::KeyPair>, ack_key: Arc<AckKey>) -> Self {
TestPacketProcessor {
local_encryption_keypair,
ack_key,
+3 -3
View File
@@ -6,7 +6,7 @@ use crate::processor::{Received, TestPacketProcessor};
use crate::{log_err, log_info, log_warn};
use futures::channel::mpsc;
use futures::StreamExt;
use nym_crypto::asymmetric::encryption;
use nym_crypto::asymmetric::x25519;
use nym_sphinx::acknowledgements::AckKey;
use nym_sphinx::receiver::{MessageReceiver, SphinxMessageReceiver};
use nym_task::TaskClient;
@@ -29,7 +29,7 @@ pub struct SimpleMessageReceiver<T, R: MessageReceiver = SphinxMessageReceiver>
impl<T> SimpleMessageReceiver<T, SphinxMessageReceiver> {
pub fn new_sphinx_receiver(
local_encryption_keypair: Arc<encryption::KeyPair>,
local_encryption_keypair: Arc<x25519::KeyPair>,
ack_key: Arc<AckKey>,
mixnet_message_receiver: mpsc::UnboundedReceiver<Vec<Vec<u8>>>,
acks_receiver: mpsc::UnboundedReceiver<Vec<Vec<u8>>>,
@@ -49,7 +49,7 @@ impl<T> SimpleMessageReceiver<T, SphinxMessageReceiver> {
impl<T, R: MessageReceiver> SimpleMessageReceiver<T, R> {
pub fn new(
local_encryption_keypair: Arc<encryption::KeyPair>,
local_encryption_keypair: Arc<x25519::KeyPair>,
ack_key: Arc<AckKey>,
mixnet_message_receiver: mpsc::UnboundedReceiver<Vec<Vec<u8>>>,
acks_receiver: mpsc::UnboundedReceiver<Vec<Vec<u8>>>,
+10
View File
@@ -39,6 +39,10 @@ pub struct NodeTester<R> {
/// Average delay an acknowledgement packet is going to get delay at a single mixnode.
average_ack_delay: Duration,
/// Specify whether any constructed packets should use the legacy format,
/// where the payload keys are explicitly attached rather than using the seeds
use_legacy_sphinx_format: bool,
// while acks are going to be ignored they still need to be constructed
// so that the gateway would be able to correctly process and forward the message
ack_key: Arc<AckKey>,
@@ -57,6 +61,7 @@ where
deterministic_route_selection: bool,
average_packet_delay: Duration,
average_ack_delay: Duration,
use_legacy_sphinx_format: bool,
ack_key: Arc<AckKey>,
) -> Self {
Self {
@@ -67,6 +72,7 @@ where
deterministic_route_selection,
average_packet_delay,
average_ack_delay,
use_legacy_sphinx_format,
ack_key,
}
}
@@ -245,6 +251,10 @@ where
impl<R: CryptoRng + Rng> FragmentPreparer for NodeTester<R> {
type Rng = R;
fn use_legacy_sphinx_format(&self) -> bool {
self.use_legacy_sphinx_format
}
fn deterministic_route_selection(&self) -> bool {
self.deterministic_route_selection
}
@@ -37,8 +37,10 @@ pub enum SurbAckRecoveryError {
}
impl SurbAck {
#[allow(clippy::too_many_arguments)]
pub fn construct<R>(
rng: &mut R,
use_legacy_sphinx_format: bool,
recipient: &Recipient,
ack_key: &AckKey,
marshaled_fragment_id: [u8; 5],
@@ -67,6 +69,7 @@ impl SurbAck {
Some(packet_size),
)?,
PacketType::Mix => NymPacket::sphinx_build(
use_legacy_sphinx_format,
packet_size,
surb_ack_payload,
&route,
+14 -14
View File
@@ -5,7 +5,7 @@
// it's already destructed).
use crate::nodes::{NodeIdentity, NODE_IDENTITY_SIZE};
use nym_crypto::asymmetric::{encryption, identity};
use nym_crypto::asymmetric::{ed25519, x25519};
use nym_sphinx_types::Destination;
use serde::de::{Error as SerdeError, Unexpected, Visitor};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
@@ -15,11 +15,11 @@ use thiserror::Error;
// Not entirely sure whether this is the correct place for those, but let's see how it's going
// to work out
pub type ClientEncryptionKey = encryption::PublicKey;
const CLIENT_ENCRYPTION_KEY_SIZE: usize = encryption::PUBLIC_KEY_SIZE;
pub type ClientEncryptionKey = x25519::PublicKey;
const CLIENT_ENCRYPTION_KEY_SIZE: usize = x25519::PUBLIC_KEY_SIZE;
pub type ClientIdentity = identity::PublicKey;
const CLIENT_IDENTITY_SIZE: usize = identity::PUBLIC_KEY_LENGTH;
pub type ClientIdentity = ed25519::PublicKey;
const CLIENT_IDENTITY_SIZE: usize = ed25519::PUBLIC_KEY_LENGTH;
pub type RecipientBytes = [u8; Recipient::LEN];
@@ -29,13 +29,13 @@ pub enum RecipientFormattingError {
MalformedRecipientError { reason: String },
#[error("recipient's identity key is malformed: {0}")]
MalformedIdentityError(identity::Ed25519RecoveryError),
MalformedIdentityError(ed25519::Ed25519RecoveryError),
#[error("recipient's encryption key is malformed: {0}")]
MalformedEncryptionKeyError(#[from] encryption::KeyRecoveryError),
MalformedEncryptionKeyError(#[from] x25519::KeyRecoveryError),
#[error("recipient gateway's identity key is malformed: {0}")]
MalformedGatewayError(identity::Ed25519RecoveryError),
MalformedGatewayError(ed25519::Ed25519RecoveryError),
}
// TODO: this should a different home... somewhere, but where?
@@ -249,9 +249,9 @@ mod tests {
fn string_conversion_works() {
let mut rng = rand::thread_rng();
let client_id_pair = identity::KeyPair::new(&mut rng);
let client_enc_pair = encryption::KeyPair::new(&mut rng);
let gateway_id_pair = identity::KeyPair::new(&mut rng);
let client_id_pair = ed25519::KeyPair::new(&mut rng);
let client_enc_pair = x25519::KeyPair::new(&mut rng);
let gateway_id_pair = ed25519::KeyPair::new(&mut rng);
let recipient = Recipient::new(
*client_id_pair.public_key(),
@@ -281,9 +281,9 @@ mod tests {
fn bytes_conversion_works() {
let mut rng = rand::thread_rng();
let client_id_pair = identity::KeyPair::new(&mut rng);
let client_enc_pair = encryption::KeyPair::new(&mut rng);
let gateway_id_pair = identity::KeyPair::new(&mut rng);
let client_id_pair = ed25519::KeyPair::new(&mut rng);
let client_enc_pair = x25519::KeyPair::new(&mut rng);
let gateway_id_pair = ed25519::KeyPair::new(&mut rng);
let recipient = Recipient::new(
*client_id_pair.public_key(),
+4 -4
View File
@@ -8,7 +8,7 @@
//! Currently, that routing information is an IP address, but in principle it can be anything
//! for as long as it's going to fit in the field.
use nym_crypto::asymmetric::identity;
use nym_crypto::asymmetric::ed25519;
use nym_sphinx_types::{NodeAddressBytes, NODE_ADDRESS_LENGTH};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
@@ -16,8 +16,8 @@ use thiserror::Error;
// Not entirely sure whether this is the correct place for those, but let's see how it's going
// to work out
pub type NodeIdentity = identity::PublicKey;
pub const NODE_IDENTITY_SIZE: usize = identity::PUBLIC_KEY_LENGTH;
pub type NodeIdentity = ed25519::PublicKey;
pub const NODE_IDENTITY_SIZE: usize = ed25519::PUBLIC_KEY_LENGTH;
/// MAX_UNPADDED_LEN represents maximum length an unpadded address could have.
/// In this case it's an ipv6 socket address (with version prefix)
@@ -199,7 +199,7 @@ impl TryFrom<NodeAddressBytes> for NymNodeRoutingAddress {
type Error = NymNodeRoutingAddressError;
fn try_from(value: NodeAddressBytes) -> Result<Self, Self::Error> {
Self::try_from_bytes(value.as_bytes_ref())
Self::try_from_bytes(value.as_bytes())
}
}
@@ -12,6 +12,7 @@ rand = { workspace = true }
bs58 = { workspace = true }
serde = { workspace = true }
thiserror = { workspace = true }
tracing = { workspace = true }
nym-crypto = { path = "../../crypto", features = ["stream_cipher", "rand"] }
nym-sphinx-addressing = { path = "../addressing" }
@@ -1,20 +1,25 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2021-2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::encryption_key::{SurbEncryptionKey, SurbEncryptionKeyError, SurbEncryptionKeySize};
use nym_crypto::{generic_array::typenum::Unsigned, Digest};
use nym_sphinx_addressing::clients::Recipient;
use nym_sphinx_addressing::nodes::{NymNodeRoutingAddress, MAX_NODE_ADDRESS_UNPADDED_LEN};
use nym_sphinx_addressing::nodes::{
NymNodeRoutingAddress, NymNodeRoutingAddressError, MAX_NODE_ADDRESS_UNPADDED_LEN,
};
use nym_sphinx_params::packet_sizes::PacketSize;
use nym_sphinx_params::{PacketType, ReplySurbKeyDigestAlgorithm};
use nym_sphinx_types::{NymPacket, SURBMaterial, SphinxError, SURB};
use nym_sphinx_types::constants::PAYLOAD_KEY_SEED_SIZE;
use nym_sphinx_types::{
NymPacket, SURBMaterial, SphinxError, HEADER_SIZE, NODE_ADDRESS_LENGTH, SURB,
X25519_WITH_EXPLICIT_PAYLOAD_KEYS_VERSION,
};
use nym_topology::{NymRouteProvider, NymTopologyError};
use rand::{CryptoRng, RngCore};
use serde::de::{Error as SerdeError, Visitor};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt::{self, Formatter};
use std::time;
use std::time::Duration;
use thiserror::Error;
#[derive(Debug, Error)]
@@ -31,6 +36,9 @@ pub enum ReplySurbError {
#[error("failed to recover reply SURB from bytes: {0}")]
RecoveryError(#[from] SphinxError),
#[error("failed to validate the first hop address of the recovered reply SURB: {0}")]
MalformedSurbFirstHop(#[from] NymNodeRoutingAddressError),
#[error("failed to recover reply SURB encryption key from bytes: {0}")]
InvalidEncryptionKeyData(#[from] SurbEncryptionKeyError),
}
@@ -80,6 +88,10 @@ impl<'de> Deserialize<'de> for ReplySurb {
}
impl ReplySurb {
/// base overhead of a reply surb that exists regardless of type or number of key materials.
pub(crate) const BASE_OVERHEAD: usize =
SurbEncryptionKeySize::USIZE + HEADER_SIZE + NODE_ADDRESS_LENGTH;
pub fn max_msg_len(packet_size: PacketSize) -> usize {
// For detailed explanation (of ack overhead) refer to common\nymsphinx\src\preparer.rs::available_plaintext_per_packet()
let ack_overhead = MAX_NODE_ADDRESS_UNPADDED_LEN + PacketSize::AckPacket.size();
@@ -91,7 +103,8 @@ impl ReplySurb {
pub fn construct<R>(
rng: &mut R,
recipient: &Recipient,
average_delay: time::Duration,
average_delay: Duration,
use_legacy_surb_format: bool,
topology: &NymRouteProvider,
) -> Result<Self, NymTopologyError>
where
@@ -101,7 +114,10 @@ impl ReplySurb {
let delays = nym_sphinx_routing::generate_hop_delays(average_delay, route.len());
let destination = recipient.as_sphinx_destination();
let surb_material = SURBMaterial::new(route, delays, destination);
let mut surb_material = SURBMaterial::new(route, delays, destination);
if use_legacy_surb_format {
surb_material = surb_material.with_version(X25519_WITH_EXPLICIT_PAYLOAD_KEYS_VERSION)
}
// this can't fail as we know we have a valid route to gateway and have correct number of delays
Ok(ReplySurb {
@@ -110,14 +126,10 @@ impl ReplySurb {
})
}
/// Returns the expected number of bytes the [`ReplySURB`] will take after serialization.
/// Returns the expected number of bytes the [`ReplySURB`] will take after serialization using the new encoding format.
/// Useful for deserialization from a bytes stream.
pub fn serialized_len() -> usize {
use nym_sphinx_types::{HEADER_SIZE, NODE_ADDRESS_LENGTH, PAYLOAD_KEY_SIZE};
// the SURB itself consists of SURB_header, first hop address and set of payload keys
// for each hop (3x mix + egress)
SurbEncryptionKeySize::USIZE + HEADER_SIZE + NODE_ADDRESS_LENGTH + 4 * PAYLOAD_KEY_SIZE
pub fn v2_serialised_len(num_hops: u8) -> usize {
Self::BASE_OVERHEAD + num_hops as usize * PAYLOAD_KEY_SEED_SIZE
}
pub fn encryption_key(&self) -> &SurbEncryptionKey {
@@ -143,7 +155,12 @@ impl ReplySurb {
let surb = match SURB::from_bytes(&bytes[SurbEncryptionKeySize::USIZE..]) {
Err(err) => return Err(ReplySurbError::RecoveryError(err)),
Ok(surb) => surb,
Ok(surb) => {
// we can't really check fully validity of the header, but at the very least we could make a sanity check
// to make sure the first hop address is a valid socket address
let _ = NymNodeRoutingAddress::try_from(surb.first_hop())?;
surb
}
};
Ok(ReplySurb {
@@ -8,9 +8,15 @@ use std::fmt::{Display, Formatter};
use std::mem;
use thiserror::Error;
use crate::requests::v1::{AdditionalSurbsV1, DataV1, HeartbeatV1};
use crate::requests::v2::{AdditionalSurbsV2, DataV2, HeartbeatV2};
#[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*;
pub(crate) mod v1;
pub(crate) mod v2;
pub const SENDER_TAG_SIZE: usize = 16;
#[derive(Debug, Error)]
@@ -103,31 +109,23 @@ pub struct RepliableMessage {
impl Display for RepliableMessage {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match &self.content {
RepliableMessageContent::Data {
message,
reply_surbs,
} => write!(
f,
"repliable {:.2} kiB data message with {} reply surbs attached from {}",
message.len() as f64 / 1024.0,
reply_surbs.len(),
self.sender_tag,
),
RepliableMessageContent::AdditionalSurbs { reply_surbs } => write!(
f,
"repliable additional surbs message ({} reply surbs attached) from {}",
reply_surbs.len(),
self.sender_tag,
),
RepliableMessageContent::Heartbeat {
additional_reply_surbs,
} => {
write!(
f,
"repliable heartbeat message ({} reply surbs attached) from {}",
additional_reply_surbs.len(),
self.sender_tag,
)
RepliableMessageContent::Data(content) => {
write!(f, "{content} from {}", self.sender_tag)
}
RepliableMessageContent::AdditionalSurbs(content) => {
write!(f, "{content} from {}", self.sender_tag)
}
RepliableMessageContent::Heartbeat(content) => {
write!(f, "{content} from {}", self.sender_tag)
}
RepliableMessageContent::DataV2(content) => {
write!(f, "{content} from {}", self.sender_tag)
}
RepliableMessageContent::AdditionalSurbsV2(content) => {
write!(f, "{content} from {}", self.sender_tag)
}
RepliableMessageContent::HeartbeatV2(content) => {
write!(f, "{content} from {}", self.sender_tag)
}
}
}
@@ -135,26 +133,43 @@ impl Display for RepliableMessage {
impl RepliableMessage {
pub fn new_data(
use_legacy_surb_format: bool,
data: Vec<u8>,
sender_tag: AnonymousSenderTag,
reply_surbs: Vec<ReplySurb>,
) -> Self {
RepliableMessage {
sender_tag,
content: RepliableMessageContent::Data {
let content = if use_legacy_surb_format {
RepliableMessageContent::Data(DataV1 {
message: data,
reply_surbs,
},
})
} else {
RepliableMessageContent::DataV2(DataV2 {
message: data,
reply_surbs,
})
};
RepliableMessage {
sender_tag,
content,
}
}
pub fn new_additional_surbs(
use_legacy_surb_format: bool,
sender_tag: AnonymousSenderTag,
reply_surbs: Vec<ReplySurb>,
) -> Self {
let content = if use_legacy_surb_format {
RepliableMessageContent::AdditionalSurbs(AdditionalSurbsV1 { reply_surbs })
} else {
RepliableMessageContent::AdditionalSurbsV2(AdditionalSurbsV2 { reply_surbs })
};
RepliableMessage {
sender_tag,
content: RepliableMessageContent::AdditionalSurbs { reply_surbs },
content,
}
}
@@ -192,35 +207,18 @@ impl RepliableMessage {
}
}
// this recovery code is shared between all variants containing reply surbs
fn recover_reply_surbs(bytes: &[u8]) -> Result<(Vec<ReplySurb>, usize), InvalidReplyRequestError> {
let mut consumed = mem::size_of::<u32>();
if bytes.len() < consumed {
return Err(InvalidReplyRequestError::RequestTooShortToDeserialize);
}
let num_surbs = u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
let surb_size = ReplySurb::serialized_len();
if bytes[consumed..].len() < num_surbs as usize * surb_size {
return Err(InvalidReplyRequestError::RequestTooShortToDeserialize);
}
let mut reply_surbs = Vec::with_capacity(num_surbs as usize);
for _ in 0..num_surbs as usize {
let surb_bytes = &bytes[consumed..consumed + surb_size];
let reply_surb = ReplySurb::from_bytes(surb_bytes)?;
reply_surbs.push(reply_surb);
consumed += surb_size;
}
Ok((reply_surbs, consumed))
}
#[derive(Debug)]
#[repr(u8)]
enum RepliableMessageContentTag {
Data = 0,
AdditionalSurbs = 1,
Heartbeat = 2,
// updated variants that slightly change SURB encoding
// to allow for variable number of hops as well as using payload key seeds
DataV2 = 3,
AdditionalSurbsV2 = 4,
HeartbeatV2 = 5,
}
impl TryFrom<u8> for RepliableMessageContentTag {
@@ -233,6 +231,11 @@ impl TryFrom<u8> for RepliableMessageContentTag {
Ok(Self::AdditionalSurbs)
}
_ if value == (RepliableMessageContentTag::Heartbeat as u8) => Ok(Self::Heartbeat),
_ if value == (RepliableMessageContentTag::DataV2 as u8) => Ok(Self::DataV2),
_ if value == (RepliableMessageContentTag::AdditionalSurbsV2 as u8) => {
Ok(Self::AdditionalSurbsV2)
}
_ if value == (RepliableMessageContentTag::HeartbeatV2 as u8) => Ok(Self::HeartbeatV2),
val => Err(InvalidReplyRequestError::InvalidRepliableContentTag { received: val }),
}
}
@@ -241,58 +244,24 @@ impl TryFrom<u8> for RepliableMessageContentTag {
// sent by original sender that initialised the communication that knows address of the remote
#[derive(Debug)]
pub enum RepliableMessageContent {
Data {
message: Vec<u8>,
reply_surbs: Vec<ReplySurb>,
},
AdditionalSurbs {
reply_surbs: Vec<ReplySurb>,
},
Heartbeat {
additional_reply_surbs: Vec<ReplySurb>,
},
Data(DataV1),
AdditionalSurbs(AdditionalSurbsV1),
Heartbeat(HeartbeatV1),
DataV2(DataV2),
AdditionalSurbsV2(AdditionalSurbsV2),
HeartbeatV2(HeartbeatV2),
}
impl RepliableMessageContent {
pub fn into_bytes(self) -> Vec<u8> {
match self {
RepliableMessageContent::Data {
message,
reply_surbs,
} => {
let num_surbs = reply_surbs.len() as u32;
num_surbs
.to_be_bytes()
.into_iter()
.chain(reply_surbs.into_iter().flat_map(|s| s.to_bytes()))
.chain(message)
.collect()
}
RepliableMessageContent::AdditionalSurbs { reply_surbs } => {
let num_surbs = reply_surbs.len() as u32;
num_surbs
.to_be_bytes()
.into_iter()
.chain(reply_surbs.into_iter().flat_map(|s| s.to_bytes()))
.collect()
}
RepliableMessageContent::Heartbeat {
additional_reply_surbs,
} => {
let num_surbs = additional_reply_surbs.len() as u32;
num_surbs
.to_be_bytes()
.into_iter()
.chain(
additional_reply_surbs
.into_iter()
.flat_map(|s| s.to_bytes()),
)
.collect()
}
RepliableMessageContent::Data(content) => content.into_bytes(),
RepliableMessageContent::AdditionalSurbs(content) => content.into_bytes(),
RepliableMessageContent::Heartbeat(content) => content.into_bytes(),
RepliableMessageContent::DataV2(content) => content.into_bytes(),
RepliableMessageContent::AdditionalSurbsV2(content) => content.into_bytes(),
RepliableMessageContent::HeartbeatV2(content) => content.into_bytes(),
}
}
@@ -304,19 +273,25 @@ impl RepliableMessageContent {
return Err(InvalidReplyRequestError::RequestTooShortToDeserialize);
}
let (reply_surbs, n) = recover_reply_surbs(bytes)?;
match tag {
RepliableMessageContentTag::Data => Ok(RepliableMessageContent::Data {
message: bytes[n..].to_vec(),
reply_surbs,
}),
RepliableMessageContentTag::AdditionalSurbs => {
Ok(RepliableMessageContent::AdditionalSurbs { reply_surbs })
RepliableMessageContentTag::Data => {
Ok(RepliableMessageContent::Data(DataV1::from_bytes(bytes)?))
}
RepliableMessageContentTag::Heartbeat => Ok(RepliableMessageContent::Heartbeat {
additional_reply_surbs: reply_surbs,
}),
RepliableMessageContentTag::AdditionalSurbs => Ok(
RepliableMessageContent::AdditionalSurbs(AdditionalSurbsV1::from_bytes(bytes)?),
),
RepliableMessageContentTag::Heartbeat => Ok(RepliableMessageContent::Heartbeat(
HeartbeatV1::from_bytes(bytes)?,
)),
RepliableMessageContentTag::DataV2 => {
Ok(RepliableMessageContent::DataV2(DataV2::from_bytes(bytes)?))
}
RepliableMessageContentTag::AdditionalSurbsV2 => Ok(
RepliableMessageContent::AdditionalSurbsV2(AdditionalSurbsV2::from_bytes(bytes)?),
),
RepliableMessageContentTag::HeartbeatV2 => Ok(RepliableMessageContent::HeartbeatV2(
HeartbeatV2::from_bytes(bytes)?,
)),
}
}
@@ -327,30 +302,22 @@ impl RepliableMessageContent {
RepliableMessageContentTag::AdditionalSurbs
}
RepliableMessageContent::Heartbeat { .. } => RepliableMessageContentTag::Heartbeat,
RepliableMessageContent::DataV2(_) => RepliableMessageContentTag::DataV2,
RepliableMessageContent::AdditionalSurbsV2(_) => {
RepliableMessageContentTag::AdditionalSurbsV2
}
RepliableMessageContent::HeartbeatV2(_) => RepliableMessageContentTag::HeartbeatV2,
}
}
fn serialized_size(&self) -> usize {
match self {
RepliableMessageContent::Data {
message,
reply_surbs,
} => {
let num_reply_surbs_tag = mem::size_of::<u32>();
num_reply_surbs_tag
+ reply_surbs.len() * ReplySurb::serialized_len()
+ message.len()
}
RepliableMessageContent::AdditionalSurbs { reply_surbs } => {
let num_reply_surbs_tag = mem::size_of::<u32>();
num_reply_surbs_tag + reply_surbs.len() * ReplySurb::serialized_len()
}
RepliableMessageContent::Heartbeat {
additional_reply_surbs,
} => {
let num_reply_surbs_tag = mem::size_of::<u32>();
num_reply_surbs_tag + additional_reply_surbs.len() * ReplySurb::serialized_len()
}
RepliableMessageContent::Data(content) => content.serialized_len(),
RepliableMessageContent::AdditionalSurbs(content) => content.serialized_len(),
RepliableMessageContent::Heartbeat(content) => content.serialized_len(),
RepliableMessageContent::DataV2(content) => content.serialized_len(),
RepliableMessageContent::AdditionalSurbsV2(content) => content.serialized_len(),
RepliableMessageContent::HeartbeatV2(content) => content.serialized_len(),
}
}
}
@@ -514,18 +481,22 @@ mod tests {
use super::*;
mod fixtures {
use crate::requests::v1::{AdditionalSurbsV1, DataV1, HeartbeatV1};
use crate::requests::v2::{AdditionalSurbsV2, DataV2, HeartbeatV2};
use crate::requests::{AnonymousSenderTag, RepliableMessageContent, ReplyMessageContent};
use crate::{ReplySurb, SurbEncryptionKey};
use nym_crypto::asymmetric::{encryption, identity};
use nym_crypto::asymmetric::{ed25519, x25519};
use nym_sphinx_addressing::clients::Recipient;
use nym_sphinx_types::{
Delay, Destination, DestinationAddressBytes, Node, NodeAddressBytes, PrivateKey,
SURBMaterial, NODE_ADDRESS_LENGTH,
SURBMaterial, NODE_ADDRESS_LENGTH, X25519_WITH_EXPLICIT_PAYLOAD_KEYS_VERSION,
};
use rand::{Rng, RngCore};
use rand_chacha::rand_core::SeedableRng;
use rand_chacha::ChaCha20Rng;
pub(crate) const LEGACY_HOPS: u8 = 4;
pub(super) fn test_rng() -> ChaCha20Rng {
let dummy_seed = [42u8; 32];
ChaCha20Rng::from_seed(dummy_seed)
@@ -544,9 +515,9 @@ mod tests {
}
pub(super) fn recipient(rng: &mut ChaCha20Rng) -> Recipient {
let client_id = identity::KeyPair::new(rng);
let client_enc = encryption::KeyPair::new(rng);
let gateway_id = identity::KeyPair::new(rng);
let client_id = ed25519::KeyPair::new(rng);
let client_enc = x25519::KeyPair::new(rng);
let gateway_id = ed25519::KeyPair::new(rng);
Recipient::new(
*client_id.public_key(),
@@ -567,11 +538,9 @@ mod tests {
}
}
pub(super) fn reply_surb(rng: &mut ChaCha20Rng) -> ReplySurb {
// due to gateway
const HOPS: u8 = 4;
let route = (0..HOPS).map(|_| node(rng)).collect();
let delays = (0..HOPS)
pub(super) fn reply_surb(rng: &mut ChaCha20Rng, legacy: bool, hops: u8) -> ReplySurb {
let route = (0..hops).map(|_| node(rng)).collect();
let delays = (0..hops)
.map(|_| Delay::new_from_nanos(rng.next_u64()))
.collect();
let mut destination_bytes = [0u8; 32];
@@ -585,50 +554,58 @@ mod tests {
identifier_bytes,
);
let surb = SURBMaterial::new(route, delays, destination)
.construct_SURB()
.unwrap();
let mut surb_material = SURBMaterial::new(route, delays, destination);
if legacy {
surb_material =
surb_material.with_version(X25519_WITH_EXPLICIT_PAYLOAD_KEYS_VERSION);
}
ReplySurb {
surb,
surb: surb_material.construct_SURB().unwrap(),
encryption_key: SurbEncryptionKey::new(rng),
}
}
pub(super) fn reply_surbs(rng: &mut ChaCha20Rng, n: usize) -> Vec<ReplySurb> {
pub(super) fn reply_surbs(
rng: &mut ChaCha20Rng,
n: usize,
legacy: bool,
hops: u8,
) -> Vec<ReplySurb> {
let mut surbs = Vec::with_capacity(n);
for _ in 0..n {
surbs.push(reply_surb(rng))
surbs.push(reply_surb(rng, legacy, hops))
}
surbs
}
pub(super) fn repliable_content_data(
pub(super) fn repliable_content_data_v1(
rng: &mut ChaCha20Rng,
msg_len: usize,
surbs: usize,
) -> RepliableMessageContent {
RepliableMessageContent::Data {
RepliableMessageContent::Data(DataV1 {
message: random_vec_u8(rng, msg_len),
reply_surbs: reply_surbs(rng, surbs),
}
reply_surbs: reply_surbs(rng, surbs, true, LEGACY_HOPS),
})
}
pub(super) fn repliable_content_surbs(
pub(super) fn repliable_content_surbs_v1(
rng: &mut ChaCha20Rng,
surbs: usize,
) -> RepliableMessageContent {
RepliableMessageContent::AdditionalSurbs {
reply_surbs: reply_surbs(rng, surbs),
}
RepliableMessageContent::AdditionalSurbs(AdditionalSurbsV1 {
reply_surbs: reply_surbs(rng, surbs, true, LEGACY_HOPS),
})
}
pub(super) fn repliable_content_heartbeat(
pub(super) fn repliable_content_heartbeat_v1(
rng: &mut ChaCha20Rng,
surbs: usize,
) -> RepliableMessageContent {
RepliableMessageContent::Heartbeat {
additional_reply_surbs: reply_surbs(rng, surbs),
}
RepliableMessageContent::Heartbeat(HeartbeatV1 {
additional_reply_surbs: reply_surbs(rng, surbs, true, LEGACY_HOPS),
})
}
pub(super) fn reply_content_data(
@@ -649,37 +626,70 @@ mod tests {
amount: surbs,
}
}
pub(super) fn repliable_content_data_v2(
rng: &mut ChaCha20Rng,
msg_len: usize,
surbs: usize,
surb_hops: u8,
) -> RepliableMessageContent {
RepliableMessageContent::DataV2(DataV2 {
message: random_vec_u8(rng, msg_len),
reply_surbs: reply_surbs(rng, surbs, false, surb_hops),
})
}
pub(super) fn repliable_content_surbs_v2(
rng: &mut ChaCha20Rng,
surbs: usize,
surb_hops: u8,
) -> RepliableMessageContent {
RepliableMessageContent::AdditionalSurbsV2(AdditionalSurbsV2 {
reply_surbs: reply_surbs(rng, surbs, false, surb_hops),
})
}
pub(super) fn repliable_content_heartbeat_v2(
rng: &mut ChaCha20Rng,
surbs: usize,
surb_hops: u8,
) -> RepliableMessageContent {
RepliableMessageContent::HeartbeatV2(HeartbeatV2 {
additional_reply_surbs: reply_surbs(rng, surbs, false, surb_hops),
})
}
}
#[cfg(test)]
mod repliable_message {
use super::*;
use crate::requests::tests::fixtures::LEGACY_HOPS;
#[test]
fn serialized_size_matches_actual_serialization() {
fn serialized_size_matches_actual_serialization_for_v1_messages() {
let mut rng = fixtures::test_rng();
let data1 = RepliableMessage {
sender_tag: fixtures::sender_tag(&mut rng),
content: fixtures::repliable_content_data(&mut rng, 10000, 0),
content: fixtures::repliable_content_data_v1(&mut rng, 10000, 0),
};
assert_eq!(data1.serialized_size(), data1.into_bytes().len());
let data2 = RepliableMessage {
sender_tag: fixtures::sender_tag(&mut rng),
content: fixtures::repliable_content_data(&mut rng, 10, 100),
content: fixtures::repliable_content_data_v1(&mut rng, 10, 100),
};
assert_eq!(data2.serialized_size(), data2.into_bytes().len());
let data3 = RepliableMessage {
sender_tag: fixtures::sender_tag(&mut rng),
content: fixtures::repliable_content_data(&mut rng, 100000, 1000),
content: fixtures::repliable_content_data_v1(&mut rng, 100000, 1000),
};
assert_eq!(data3.serialized_size(), data3.into_bytes().len());
let additional_surbs1 = RepliableMessage {
sender_tag: fixtures::sender_tag(&mut rng),
content: fixtures::repliable_content_surbs(&mut rng, 1),
content: fixtures::repliable_content_surbs_v1(&mut rng, 1),
};
assert_eq!(
additional_surbs1.serialized_size(),
@@ -688,7 +698,7 @@ mod tests {
let additional_surbs2 = RepliableMessage {
sender_tag: fixtures::sender_tag(&mut rng),
content: fixtures::repliable_content_surbs(&mut rng, 1000),
content: fixtures::repliable_content_surbs_v1(&mut rng, 1000),
};
assert_eq!(
additional_surbs2.serialized_size(),
@@ -697,53 +707,173 @@ mod tests {
let heartbeat1 = RepliableMessage {
sender_tag: fixtures::sender_tag(&mut rng),
content: fixtures::repliable_content_heartbeat(&mut rng, 1),
content: fixtures::repliable_content_heartbeat_v1(&mut rng, 1),
};
assert_eq!(heartbeat1.serialized_size(), heartbeat1.into_bytes().len());
let heartbeat2 = RepliableMessage {
sender_tag: fixtures::sender_tag(&mut rng),
content: fixtures::repliable_content_heartbeat(&mut rng, 1000),
content: fixtures::repliable_content_heartbeat_v1(&mut rng, 1000),
};
assert_eq!(heartbeat2.serialized_size(), heartbeat2.into_bytes().len());
}
#[test]
fn serialized_size_matches_actual_serialization_for_v2_messages() {
let mut rng = fixtures::test_rng();
let data1 = RepliableMessage {
sender_tag: fixtures::sender_tag(&mut rng),
content: fixtures::repliable_content_data_v2(&mut rng, 10000, 0, LEGACY_HOPS),
};
assert_eq!(data1.serialized_size(), data1.into_bytes().len());
let data2 = RepliableMessage {
sender_tag: fixtures::sender_tag(&mut rng),
content: fixtures::repliable_content_data_v2(&mut rng, 10, 100, LEGACY_HOPS),
};
assert_eq!(data2.serialized_size(), data2.into_bytes().len());
let data3 = RepliableMessage {
sender_tag: fixtures::sender_tag(&mut rng),
content: fixtures::repliable_content_data_v2(&mut rng, 100000, 1000, LEGACY_HOPS),
};
assert_eq!(data3.serialized_size(), data3.into_bytes().len());
let data4 = RepliableMessage {
sender_tag: fixtures::sender_tag(&mut rng),
content: fixtures::repliable_content_data_v2(&mut rng, 100000, 1000, 1),
};
assert_eq!(data4.serialized_size(), data4.into_bytes().len());
let additional_surbs1 = RepliableMessage {
sender_tag: fixtures::sender_tag(&mut rng),
content: fixtures::repliable_content_surbs_v2(&mut rng, 1, LEGACY_HOPS),
};
assert_eq!(
additional_surbs1.serialized_size(),
additional_surbs1.into_bytes().len()
);
let additional_surbs2 = RepliableMessage {
sender_tag: fixtures::sender_tag(&mut rng),
content: fixtures::repliable_content_surbs_v2(&mut rng, 1000, LEGACY_HOPS),
};
assert_eq!(
additional_surbs2.serialized_size(),
additional_surbs2.into_bytes().len()
);
let additional_surbs3 = RepliableMessage {
sender_tag: fixtures::sender_tag(&mut rng),
content: fixtures::repliable_content_surbs_v2(&mut rng, 1000, 1),
};
assert_eq!(
additional_surbs3.serialized_size(),
additional_surbs3.into_bytes().len()
);
let heartbeat1 = RepliableMessage {
sender_tag: fixtures::sender_tag(&mut rng),
content: fixtures::repliable_content_heartbeat_v2(&mut rng, 1, LEGACY_HOPS),
};
assert_eq!(heartbeat1.serialized_size(), heartbeat1.into_bytes().len());
let heartbeat2 = RepliableMessage {
sender_tag: fixtures::sender_tag(&mut rng),
content: fixtures::repliable_content_heartbeat_v2(&mut rng, 1000, LEGACY_HOPS),
};
assert_eq!(heartbeat2.serialized_size(), heartbeat2.into_bytes().len());
let heartbeat3 = RepliableMessage {
sender_tag: fixtures::sender_tag(&mut rng),
content: fixtures::repliable_content_heartbeat_v2(&mut rng, 1000, 1),
};
assert_eq!(heartbeat3.serialized_size(), heartbeat3.into_bytes().len());
}
}
#[cfg(test)]
mod repliable_message_content {
use super::*;
use crate::requests::tests::fixtures::LEGACY_HOPS;
#[test]
fn serialized_size_matches_actual_serialization() {
fn serialized_size_matches_actual_serialization_for_v1_messages() {
let mut rng = fixtures::test_rng();
let data1 = fixtures::repliable_content_data(&mut rng, 10000, 0);
let data1 = fixtures::repliable_content_data_v1(&mut rng, 10000, 0);
assert_eq!(data1.serialized_size(), data1.into_bytes().len());
let data2 = fixtures::repliable_content_data(&mut rng, 10, 100);
let data2 = fixtures::repliable_content_data_v1(&mut rng, 10, 100);
assert_eq!(data2.serialized_size(), data2.into_bytes().len());
let data3 = fixtures::repliable_content_data(&mut rng, 100000, 1000);
let data3 = fixtures::repliable_content_data_v1(&mut rng, 100000, 1000);
assert_eq!(data3.serialized_size(), data3.into_bytes().len());
let additional_surbs1 = fixtures::repliable_content_surbs(&mut rng, 1);
let additional_surbs1 = fixtures::repliable_content_surbs_v1(&mut rng, 1);
assert_eq!(
additional_surbs1.serialized_size(),
additional_surbs1.into_bytes().len()
);
let additional_surbs2 = fixtures::repliable_content_surbs(&mut rng, 1000);
let additional_surbs2 = fixtures::repliable_content_surbs_v1(&mut rng, 1000);
assert_eq!(
additional_surbs2.serialized_size(),
additional_surbs2.into_bytes().len()
);
let heartbeat1 = fixtures::repliable_content_heartbeat(&mut rng, 1);
let heartbeat1 = fixtures::repliable_content_heartbeat_v1(&mut rng, 1);
assert_eq!(heartbeat1.serialized_size(), heartbeat1.into_bytes().len());
let heartbeat2 = fixtures::repliable_content_heartbeat(&mut rng, 1000);
let heartbeat2 = fixtures::repliable_content_heartbeat_v1(&mut rng, 1000);
assert_eq!(heartbeat2.serialized_size(), heartbeat2.into_bytes().len());
}
#[test]
fn serialized_size_matches_actual_serialization_for_v2_messages() {
let mut rng = fixtures::test_rng();
let data1 = fixtures::repliable_content_data_v2(&mut rng, 10000, 0, LEGACY_HOPS);
assert_eq!(data1.serialized_size(), data1.into_bytes().len());
let data2 = fixtures::repliable_content_data_v2(&mut rng, 10, 100, LEGACY_HOPS);
assert_eq!(data2.serialized_size(), data2.into_bytes().len());
let data3 = fixtures::repliable_content_data_v2(&mut rng, 100000, 1000, LEGACY_HOPS);
assert_eq!(data3.serialized_size(), data3.into_bytes().len());
let data4 = fixtures::repliable_content_data_v2(&mut rng, 100000, 1000, 1);
assert_eq!(data4.serialized_size(), data4.into_bytes().len());
let additional_surbs1 = fixtures::repliable_content_surbs_v2(&mut rng, 1, LEGACY_HOPS);
assert_eq!(
additional_surbs1.serialized_size(),
additional_surbs1.into_bytes().len()
);
let additional_surbs2 =
fixtures::repliable_content_surbs_v2(&mut rng, 1000, LEGACY_HOPS);
assert_eq!(
additional_surbs2.serialized_size(),
additional_surbs2.into_bytes().len()
);
let additional_surbs3 = fixtures::repliable_content_surbs_v2(&mut rng, 1000, 1);
assert_eq!(
additional_surbs3.serialized_size(),
additional_surbs3.into_bytes().len()
);
let heartbeat1 = fixtures::repliable_content_heartbeat_v2(&mut rng, 1, LEGACY_HOPS);
assert_eq!(heartbeat1.serialized_size(), heartbeat1.into_bytes().len());
let heartbeat2 = fixtures::repliable_content_heartbeat_v2(&mut rng, 1000, LEGACY_HOPS);
assert_eq!(heartbeat2.serialized_size(), heartbeat2.into_bytes().len());
let heartbeat3 = fixtures::repliable_content_heartbeat_v2(&mut rng, 1000, 1);
assert_eq!(heartbeat3.serialized_size(), heartbeat3.into_bytes().len());
}
}
#[cfg(test)]
@@ -0,0 +1,176 @@
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::requests::InvalidReplyRequestError;
use crate::ReplySurb;
use nym_sphinx_types::PAYLOAD_KEY_SIZE;
use std::fmt::Display;
use std::mem;
use tracing::{error, warn};
const fn v1_reply_surb_serialised_len() -> usize {
// the SURB itself consists of SURB_header, first hop address and set of payload keys
// for each hop (3x mix + egress)
ReplySurb::BASE_OVERHEAD + 4 * PAYLOAD_KEY_SIZE
}
fn v1_reply_surbs_serialised_len(surbs: &[ReplySurb]) -> usize {
// sanity checks; this should probably be removed later on
if let Some(reply_surb) = surbs.first() {
if reply_surb.surb.uses_key_seeds() {
error!("using v1 surbs encoding with updated structure - the surbs will be unusable")
}
}
// when serialising surbs are always prepended with u32-encoded count
4 + surbs.len() * v1_reply_surb_serialised_len()
}
// this recovery code is shared between all legacy variants containing reply surbs
// NUM_SURBS (u32) || SURB_DATA
fn recover_reply_surbs_v1(
bytes: &[u8],
) -> Result<(Vec<ReplySurb>, usize), InvalidReplyRequestError> {
let mut consumed = mem::size_of::<u32>();
if bytes.len() < consumed {
return Err(InvalidReplyRequestError::RequestTooShortToDeserialize);
}
let num_surbs = u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
let surb_size = v1_reply_surb_serialised_len();
if bytes[consumed..].len() < num_surbs as usize * surb_size {
return Err(InvalidReplyRequestError::RequestTooShortToDeserialize);
}
let mut reply_surbs = Vec::with_capacity(num_surbs as usize);
for _ in 0..num_surbs as usize {
let surb_bytes = &bytes[consumed..consumed + surb_size];
let reply_surb = ReplySurb::from_bytes(surb_bytes)?;
reply_surbs.push(reply_surb);
consumed += surb_size;
}
Ok((reply_surbs, consumed))
}
// length (u32) prefixed reply surbs with legacy serialisation of 4 hops and full payload keys attached
fn reply_surbs_bytes_v1(reply_surbs: &[ReplySurb]) -> impl Iterator<Item = u8> + use<'_> {
let num_surbs = reply_surbs.len() as u32;
num_surbs
.to_be_bytes()
.into_iter()
.chain(reply_surbs.iter().flat_map(|s| s.to_bytes()))
}
#[derive(Debug)]
pub struct DataV1 {
pub message: Vec<u8>,
pub reply_surbs: Vec<ReplySurb>,
}
impl Display for DataV1 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
write!(
f,
"V1 repliable {:.2} kiB data message with {} reply surbs attached",
self.message.len() as f64 / 1024.0,
self.reply_surbs.len(),
)
}
}
#[derive(Debug)]
pub struct AdditionalSurbsV1 {
pub reply_surbs: Vec<ReplySurb>,
}
impl Display for AdditionalSurbsV1 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
write!(
f,
"V1 repliable additional surbs message ({} reply surbs attached)",
self.reply_surbs.len(),
)
}
}
#[derive(Debug)]
pub struct HeartbeatV1 {
pub additional_reply_surbs: Vec<ReplySurb>,
}
impl Display for HeartbeatV1 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
write!(
f,
"V1 repliable heartbeat message ({} reply surbs attached)",
self.additional_reply_surbs.len(),
)
}
}
impl DataV1 {
pub fn into_bytes(self) -> Vec<u8> {
reply_surbs_bytes_v1(&self.reply_surbs)
.chain(self.message)
.collect()
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, InvalidReplyRequestError> {
let (reply_surbs, n) = recover_reply_surbs_v1(bytes)?;
Ok(DataV1 {
message: bytes[n..].to_vec(),
reply_surbs,
})
}
pub fn serialized_len(&self) -> usize {
v1_reply_surbs_serialised_len(&self.reply_surbs) + self.message.len()
}
}
impl AdditionalSurbsV1 {
pub fn into_bytes(self) -> Vec<u8> {
reply_surbs_bytes_v1(&self.reply_surbs).collect()
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, InvalidReplyRequestError> {
let (reply_surbs, n) = recover_reply_surbs_v1(bytes)?;
if n != bytes.len() {
let trailing = bytes.len() - n;
warn!("trailing {trailing} bytes after v1 additional surbs message");
}
Ok(AdditionalSurbsV1 { reply_surbs })
}
pub fn serialized_len(&self) -> usize {
v1_reply_surbs_serialised_len(&self.reply_surbs)
}
}
impl HeartbeatV1 {
pub fn into_bytes(self) -> Vec<u8> {
reply_surbs_bytes_v1(&self.additional_reply_surbs).collect()
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, InvalidReplyRequestError> {
let (additional_reply_surbs, n) = recover_reply_surbs_v1(bytes)?;
if n != bytes.len() {
let trailing = bytes.len() - n;
warn!("trailing {trailing} bytes after v1 heartbeat message");
}
Ok(HeartbeatV1 {
additional_reply_surbs,
})
}
pub fn serialized_len(&self) -> usize {
v1_reply_surbs_serialised_len(&self.additional_reply_surbs)
}
}
@@ -0,0 +1,187 @@
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::requests::InvalidReplyRequestError;
use crate::ReplySurb;
use nym_sphinx_types::constants::PAYLOAD_KEY_SEED_SIZE;
use std::fmt::Display;
use std::iter::once;
use tracing::{error, warn};
const fn v2_reply_surb_serialised_len(num_hops: u8) -> usize {
ReplySurb::BASE_OVERHEAD + num_hops as usize * PAYLOAD_KEY_SEED_SIZE
}
// sphinx doesn't support more than 5 hops (so cast to u8 is safe)
// ASSUMPTION: all surbs are generated with the same parameters (if they're not, then the client is hurting itself)
fn reply_surbs_hops(reply_surbs: &[ReplySurb]) -> u8 {
reply_surbs
.first()
.map(|reply_surb| reply_surb.surb.materials_count() as u8)
.unwrap_or_default()
}
fn v2_reply_surbs_serialised_len(surbs: &[ReplySurb]) -> usize {
let num_surbs = surbs.len();
let num_hops = reply_surbs_hops(surbs);
// sanity checks; this should probably be removed later on
if let Some(reply_surb) = surbs.first() {
if !reply_surb.surb.uses_key_seeds() {
error!("using v2 surbs encoding with legacy structure - the surbs will be unusable")
}
}
// when serialising surbs are always prepended with u16-encoded count an u8-encoded number of hops
3 + num_surbs * v2_reply_surb_serialised_len(num_hops)
}
// NUM_SURBS (u16) || HOPS (u8) || SURB_DATA
fn recover_reply_surbs_v2(
bytes: &[u8],
) -> Result<(Vec<ReplySurb>, usize), InvalidReplyRequestError> {
if bytes.len() < 2 {
return Err(InvalidReplyRequestError::RequestTooShortToDeserialize);
}
// we're not attaching more than 65k surbs...
let num_surbs = u16::from_be_bytes([bytes[0], bytes[1]]);
let num_hops = bytes[2];
let mut consumed = 3;
let surb_size = ReplySurb::v2_serialised_len(num_hops);
if bytes[consumed..].len() < num_surbs as usize * surb_size {
return Err(InvalidReplyRequestError::RequestTooShortToDeserialize);
}
let mut reply_surbs = Vec::with_capacity(num_surbs as usize);
for _ in 0..num_surbs as usize {
let surb_bytes = &bytes[consumed..consumed + surb_size];
let reply_surb = ReplySurb::from_bytes(surb_bytes)?;
reply_surbs.push(reply_surb);
consumed += surb_size;
}
Ok((reply_surbs, consumed))
}
fn reply_surbs_bytes_v2(reply_surbs: &[ReplySurb]) -> impl Iterator<Item = u8> + use<'_> {
let num_surbs = reply_surbs.len() as u16;
let num_hops = reply_surbs_hops(reply_surbs);
num_surbs
.to_be_bytes()
.into_iter()
.chain(once(num_hops))
.chain(reply_surbs.iter().flat_map(|surb| surb.to_bytes()))
}
#[derive(Debug)]
pub struct DataV2 {
pub message: Vec<u8>,
pub reply_surbs: Vec<ReplySurb>,
}
impl Display for DataV2 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
write!(
f,
"V2 repliable {:.2} kiB data message with {} reply surbs attached",
self.message.len() as f64 / 1024.0,
self.reply_surbs.len(),
)
}
}
#[derive(Debug)]
pub struct AdditionalSurbsV2 {
pub reply_surbs: Vec<ReplySurb>,
}
impl Display for AdditionalSurbsV2 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
write!(
f,
"V2 repliable additional surbs message ({} reply surbs attached)",
self.reply_surbs.len(),
)
}
}
#[derive(Debug)]
pub struct HeartbeatV2 {
pub additional_reply_surbs: Vec<ReplySurb>,
}
impl Display for HeartbeatV2 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
write!(
f,
"V2 repliable heartbeat message ({} reply surbs attached)",
self.additional_reply_surbs.len(),
)
}
}
impl DataV2 {
pub fn into_bytes(self) -> Vec<u8> {
reply_surbs_bytes_v2(&self.reply_surbs)
.chain(self.message)
.collect()
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, InvalidReplyRequestError> {
let (reply_surbs, n) = recover_reply_surbs_v2(bytes)?;
Ok(DataV2 {
message: bytes[n..].to_vec(),
reply_surbs,
})
}
pub fn serialized_len(&self) -> usize {
v2_reply_surbs_serialised_len(&self.reply_surbs) + self.message.len()
}
}
impl AdditionalSurbsV2 {
pub fn into_bytes(self) -> Vec<u8> {
reply_surbs_bytes_v2(&self.reply_surbs).collect()
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, InvalidReplyRequestError> {
let (reply_surbs, n) = recover_reply_surbs_v2(bytes)?;
if n != bytes.len() {
let trailing = bytes.len() - n;
warn!("trailing {trailing} bytes after v2 additional surbs message");
}
Ok(AdditionalSurbsV2 { reply_surbs })
}
pub fn serialized_len(&self) -> usize {
v2_reply_surbs_serialised_len(&self.reply_surbs)
}
}
impl HeartbeatV2 {
pub fn into_bytes(self) -> Vec<u8> {
reply_surbs_bytes_v2(&self.additional_reply_surbs).collect()
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, InvalidReplyRequestError> {
let (additional_reply_surbs, n) = recover_reply_surbs_v2(bytes)?;
if n != bytes.len() {
let trailing = bytes.len() - n;
warn!("trailing {trailing} bytes after v2 heartbeat message");
}
Ok(HeartbeatV2 {
additional_reply_surbs,
})
}
pub fn serialized_len(&self) -> usize {
v2_reply_surbs_serialised_len(&self.additional_reply_surbs)
}
}
+5
View File
@@ -34,6 +34,7 @@ pub enum CoverMessageError {
pub fn generate_loop_cover_surb_ack<R>(
rng: &mut R,
use_legacy_sphinx_format: bool,
topology: &NymRouteProvider,
ack_key: &AckKey,
full_address: &Recipient,
@@ -45,6 +46,7 @@ where
{
Ok(SurbAck::construct(
rng,
use_legacy_sphinx_format,
full_address,
ack_key,
COVER_FRAG_ID.to_bytes(),
@@ -57,6 +59,7 @@ where
#[allow(clippy::too_many_arguments)]
pub fn generate_loop_cover_packet<R>(
rng: &mut R,
use_legacy_sphinx_format: bool,
topology: &NymRouteProvider,
ack_key: &AckKey,
full_address: &Recipient,
@@ -71,6 +74,7 @@ where
// we don't care about total ack delay - we will not be retransmitting it anyway
let (_, ack_bytes) = generate_loop_cover_surb_ack(
rng,
use_legacy_sphinx_format,
topology,
ack_key,
full_address,
@@ -126,6 +130,7 @@ where
// once merged, that's an easy rng injection point for sphinx packets : )
let packet = match packet_type {
PacketType::Mix => NymPacket::sphinx_build(
use_legacy_sphinx_format,
packet_size.payload_size(),
packet_payload,
&route,
+33 -93
View File
@@ -5,6 +5,7 @@ use crate::packet::{FramedNymPacket, Header};
use bytes::{Buf, BufMut, BytesMut};
use nym_sphinx_params::packet_sizes::{InvalidPacketSize, PacketSize};
use nym_sphinx_params::packet_types::InvalidPacketType;
use nym_sphinx_params::packet_version::{InvalidPacketVersion, PacketVersion};
use nym_sphinx_params::PacketType;
use nym_sphinx_types::{NymPacket, NymPacketError};
use std::io;
@@ -13,16 +14,25 @@ use tokio_util::codec::{Decoder, Encoder};
#[derive(Error, Debug)]
pub enum NymCodecError {
#[error("the packet size information was malformed - {0}")]
#[error("the packet size information was malformed: {0}")]
InvalidPacketSize(#[from] InvalidPacketSize),
#[error("the packet mode information was malformed - {0}")]
#[error("the packet mode information was malformed: {0}")]
InvalidPacketType(#[from] InvalidPacketType),
#[error("encountered an IO error - {0}")]
#[error("the packet version information was malformed: {0}")]
InvalidPacketVersion(#[from] InvalidPacketVersion),
#[error("received unsupported packet version {received}. max supported is {max_supported}")]
UnsupportedPacketVersion {
received: PacketVersion,
max_supported: PacketVersion,
},
#[error("encountered an IO error: {0}")]
IoError(#[from] io::Error),
#[error("encountered a packet error - {0}")]
#[error("encountered a packet error: {0}")]
NymPacket(#[from] NymPacketError),
#[error("could not convert to bytes")]
@@ -56,7 +66,7 @@ impl Decoder for NymCodec {
if src.is_empty() {
// can't do anything if we have no bytes, but let's reserve enough for the most
// conservative case, i.e. receiving an ack packet
src.reserve(Header::LEGACY_SIZE + PacketSize::AckPacket.size());
src.reserve(Header::SIZE + PacketSize::AckPacket.size());
return Ok(None);
}
@@ -68,7 +78,7 @@ impl Decoder for NymCodec {
};
let packet_size = header.packet_size.size();
let frame_len = header.size() + packet_size;
let frame_len = Header::SIZE + packet_size;
if src.len() < frame_len {
// we don't have enough bytes to read the rest of frame
@@ -77,7 +87,7 @@ impl Decoder for NymCodec {
}
// advance buffer past the header - at this point we have enough bytes
src.advance(header.size());
src.advance(Header::SIZE);
let packet_bytes = src.split_to(packet_size);
let packet = if let Some(slice) = packet_bytes.get(..) {
// here it could be debatable whether stream is corrupt or not,
@@ -104,11 +114,11 @@ impl Decoder for NymCodec {
// we also assume the next packet coming from the same client will use exactly the same versioning
// as the current packet
let mut allocate_for_next_packet = header.size() + PacketSize::AckPacket.size();
let mut allocate_for_next_packet = Header::SIZE + PacketSize::AckPacket.size();
if !src.is_empty() {
match Header::decode(src) {
Ok(Some(next_header)) => {
allocate_for_next_packet = next_header.size() + next_header.packet_size.size();
allocate_for_next_packet = Header::SIZE + next_header.packet_size.size();
}
Ok(None) => {
// we don't have enough information to know how much to reserve, fallback to the ack case
@@ -199,8 +209,15 @@ mod packet_encoding {
SphinxDelay::new_from_nanos(42),
SphinxDelay::new_from_nanos(42),
];
NymPacket::sphinx_build(size.payload_size(), b"foomp", &route, &destination, &delays)
.unwrap()
NymPacket::sphinx_build(
false,
size.payload_size(),
b"foomp",
&route,
&destination,
&delays,
)
.unwrap()
}
#[test]
@@ -252,34 +269,10 @@ mod packet_encoding {
assert!(NymCodec.decode(&mut empty_bytes).unwrap().is_none());
assert_eq!(
empty_bytes.capacity(),
Header::LEGACY_SIZE + PacketSize::AckPacket.size()
Header::SIZE + PacketSize::AckPacket.size()
);
}
#[test]
fn for_bytes_with_legacy_header() {
// if header gets decoded there should be enough bytes for the entire frame
let packet_sizes = vec![
PacketSize::AckPacket,
PacketSize::RegularPacket,
PacketSize::ExtendedPacket8,
PacketSize::ExtendedPacket16,
PacketSize::ExtendedPacket32,
];
for packet_size in packet_sizes {
let header = Header {
packet_version: PacketVersion::Legacy,
packet_size,
..Default::default()
};
let mut bytes = BytesMut::new();
header.encode(&mut bytes);
assert!(NymCodec.decode(&mut bytes).unwrap().is_none());
assert_eq!(bytes.capacity(), Header::LEGACY_SIZE + packet_size.size())
}
}
#[test]
fn for_bytes_with_versioned_header() {
// if header gets decoded there should be enough bytes for the entire frame
@@ -292,7 +285,7 @@ mod packet_encoding {
];
for packet_size in packet_sizes {
let header = Header {
packet_version: PacketVersion::Versioned(123),
packet_version: PacketVersion::new(),
packet_size,
..Default::default()
};
@@ -300,33 +293,10 @@ mod packet_encoding {
header.encode(&mut bytes);
assert!(NymCodec.decode(&mut bytes).unwrap().is_none());
assert_eq!(
bytes.capacity(),
Header::VERSIONED_SIZE + packet_size.size()
)
assert_eq!(bytes.capacity(), Header::SIZE + packet_size.size())
}
}
#[test]
fn for_full_frame_with_legacy_header() {
// if full frame is used exactly, there should be enough space for header + ack packet
let packet = FramedNymPacket {
header: Header {
packet_version: PacketVersion::Legacy,
..Default::default()
},
packet: make_valid_sphinx_packet(Default::default()),
};
let mut bytes = BytesMut::new();
NymCodec.encode(packet, &mut bytes).unwrap();
assert!(NymCodec.decode(&mut bytes).unwrap().is_some());
assert_eq!(
bytes.capacity(),
Header::LEGACY_SIZE + PacketSize::AckPacket.size()
);
}
#[test]
fn for_full_frame_with_versioned_header() {
// if full frame is used exactly, there should be enough space for header + ack packet
@@ -340,40 +310,10 @@ mod packet_encoding {
assert!(NymCodec.decode(&mut bytes).unwrap().is_some());
assert_eq!(
bytes.capacity(),
Header::VERSIONED_SIZE + PacketSize::AckPacket.size()
Header::SIZE + PacketSize::AckPacket.size()
);
}
#[test]
fn for_full_frame_with_extra_bytes_with_legacy_header() {
// if there was at least 2 byte left, there should be enough space for entire next frame
let packet_sizes = vec![
PacketSize::AckPacket,
PacketSize::RegularPacket,
PacketSize::ExtendedPacket8,
PacketSize::ExtendedPacket16,
PacketSize::ExtendedPacket32,
];
for packet_size in packet_sizes {
let first_packet = FramedNymPacket {
header: Header {
packet_version: PacketVersion::Legacy,
..Default::default()
},
packet: make_valid_sphinx_packet(Default::default()),
};
let mut bytes = BytesMut::new();
NymCodec.encode(first_packet, &mut bytes).unwrap();
bytes.put_u8(packet_size as u8);
bytes.put_u8(PacketType::default() as u8);
assert!(NymCodec.decode(&mut bytes).unwrap().is_some());
assert!(bytes.capacity() >= Header::LEGACY_SIZE + packet_size.size())
}
}
#[test]
fn for_full_frame_with_extra_bytes_with_versioned_header() {
// if there was at least 3 byte left, there should be enough space for entire next frame
@@ -393,7 +333,7 @@ mod packet_encoding {
let mut bytes = BytesMut::new();
NymCodec.encode(first_packet, &mut bytes).unwrap();
bytes.put_u8(PacketVersion::new_versioned(123).as_u8().unwrap());
bytes.put_u8(PacketVersion::new().as_u8());
bytes.put_u8(packet_size as u8);
bytes.put_u8(PacketType::default() as u8);
assert!(NymCodec.decode(&mut bytes).unwrap().is_some());
+54 -59
View File
@@ -4,7 +4,7 @@
use crate::codec::NymCodecError;
use bytes::{BufMut, BytesMut};
use nym_sphinx_params::packet_sizes::PacketSize;
use nym_sphinx_params::packet_version::PacketVersion;
use nym_sphinx_params::packet_version::{PacketVersion, CURRENT_PACKET_VERSION};
use nym_sphinx_params::PacketType;
use nym_sphinx_types::NymPacket;
@@ -81,8 +81,7 @@ pub struct Header {
}
impl Header {
pub(crate) const LEGACY_SIZE: usize = 2;
pub(crate) const VERSIONED_SIZE: usize = 3;
pub(crate) const SIZE: usize = 3;
pub fn outfox() -> Header {
Header {
@@ -92,53 +91,39 @@ impl Header {
}
}
pub(crate) fn size(&self) -> usize {
if self.packet_version.is_legacy() {
Self::LEGACY_SIZE
} else {
Self::VERSIONED_SIZE
}
}
pub(crate) fn encode(&self, dst: &mut BytesMut) {
// we reserve one byte for `packet_size` and the other for `mode`
dst.reserve(Self::LEGACY_SIZE);
if let Some(version) = self.packet_version.as_u8() {
dst.reserve(Self::VERSIONED_SIZE);
dst.put_u8(version)
}
dst.reserve(Self::SIZE);
dst.put_u8(self.packet_version.as_u8());
dst.put_u8(self.packet_size as u8);
dst.put_u8(self.packet_type as u8);
// reserve bytes for the actual packet
dst.reserve(self.packet_size.size());
}
pub(crate) fn decode(src: &mut BytesMut) -> Result<Option<Self>, NymCodecError> {
if src.len() < Self::LEGACY_SIZE {
if src.len() < Self::SIZE {
// can't do anything if we don't have enough bytes - but reserve enough for the next call
src.reserve(Self::LEGACY_SIZE);
src.reserve(Self::SIZE);
return Ok(None);
}
let packet_version = PacketVersion::from(src[0]);
if packet_version.is_legacy() {
Ok(Some(Header {
packet_version,
packet_size: PacketSize::try_from(src[0])?,
packet_type: PacketType::try_from(src[1])?,
}))
} else if src.len() < Self::VERSIONED_SIZE {
// we're missing that 1 byte to read the full header...
src.reserve(Self::VERSIONED_SIZE);
Ok(None)
} else {
Ok(Some(Header {
packet_version,
packet_size: PacketSize::try_from(src[1])?,
packet_type: PacketType::try_from(src[2])?,
}))
let packet_version = PacketVersion::try_from(src[0])?;
if packet_version > CURRENT_PACKET_VERSION {
// received an unsupported packet version - we don't know how it's meant to look like!
// (this is in preparation for the dual support of breaking sphinx changes)
return Err(NymCodecError::UnsupportedPacketVersion {
received: packet_version,
max_supported: CURRENT_PACKET_VERSION,
});
}
Ok(Some(Header {
packet_version,
packet_size: PacketSize::try_from(src[1])?,
packet_type: PacketType::try_from(src[2])?,
}))
}
}
@@ -165,7 +150,7 @@ mod header_encoding {
// due to the hack used to get legacy mode compatibility
let mut bytes = BytesMut::from(
[
PacketVersion::new_versioned(123).as_u8().unwrap(),
PacketVersion::new().as_u8(),
unknown_packet_size,
PacketType::default() as u8,
]
@@ -180,7 +165,14 @@ mod header_encoding {
// make sure this is still 'unknown' for if we make changes in the future
assert!(PacketType::try_from(unknown_packet_type).is_err());
let mut bytes = BytesMut::from([PacketSize::default() as u8, unknown_packet_type].as_ref());
let mut bytes = BytesMut::from(
[
PacketVersion::new().as_u8(),
PacketSize::default() as u8,
unknown_packet_type,
]
.as_ref(),
);
assert!(Header::decode(&mut bytes).is_err())
}
@@ -189,16 +181,16 @@ mod header_encoding {
let mut empty_bytes = BytesMut::new();
let decode_attempt_1 = Header::decode(&mut empty_bytes).unwrap();
assert!(decode_attempt_1.is_none());
assert!(empty_bytes.capacity() > Header::LEGACY_SIZE);
assert!(empty_bytes.capacity() > Header::SIZE);
let mut empty_bytes = BytesMut::with_capacity(1);
let decode_attempt_2 = Header::decode(&mut empty_bytes).unwrap();
assert!(decode_attempt_2.is_none());
assert!(empty_bytes.capacity() > Header::LEGACY_SIZE);
assert!(empty_bytes.capacity() > Header::SIZE);
}
#[test]
fn header_encoding_reserves_enough_bytes_for_full_sphinx_packet_in_legacy_mode() {
fn header_encoding_reserves_enough_bytes_for_full_sphinx_packet_() {
let packet_sizes = vec![
PacketSize::AckPacket,
PacketSize::RegularPacket,
@@ -208,7 +200,7 @@ mod header_encoding {
];
for packet_size in packet_sizes {
let header = Header {
packet_version: PacketVersion::Legacy,
packet_version: PacketVersion::new(),
packet_size,
..Default::default()
};
@@ -219,23 +211,26 @@ mod header_encoding {
}
#[test]
fn header_encoding_reserves_enough_bytes_for_full_sphinx_packet_in_versioned_mode() {
let packet_sizes = vec![
PacketSize::AckPacket,
PacketSize::RegularPacket,
PacketSize::ExtendedPacket8,
PacketSize::ExtendedPacket16,
PacketSize::ExtendedPacket32,
];
for packet_size in packet_sizes {
let header = Header {
packet_version: PacketVersion::Versioned(123),
packet_size,
..Default::default()
};
let mut bytes = BytesMut::new();
header.encode(&mut bytes);
assert_eq!(bytes.capacity(), bytes.len() + packet_size.size())
fn header_decoding_will_reject_future_versions() {
let future_version = PacketVersion::try_from(123).unwrap();
let unchecked_header = Header {
packet_version: future_version,
packet_size: PacketSize::RegularPacket,
packet_type: PacketType::Mix,
};
let mut bytes = BytesMut::new();
unchecked_header.encode(&mut bytes);
match Header::decode(&mut bytes).unwrap_err() {
NymCodecError::UnsupportedPacketVersion {
received,
max_supported,
} => {
assert_eq!(received, future_version);
assert_eq!(max_supported, CURRENT_PACKET_VERSION);
}
_ => panic!("unexpected error variant"),
}
}
}
-11
View File
@@ -22,17 +22,6 @@ pub mod packet_version;
pub const FRAG_ID_LEN: usize = 5;
pub type SerializedFragmentIdentifier = [u8; FRAG_ID_LEN];
// wait, wait, but why are we starting with version 7?
// when packet header gets serialized, the following bytes (in that order) are put onto the wire:
// - packet_version (starting with v1.1.0)
// - packet_size indicator
// - packet_type
// it also just so happens that the only valid values for packet_size indicator include values 1-6
// therefore if we receive byte `7` (or larger than that) we'll know we received a versioned packet,
// otherwise we should treat it as legacy
/// Increment it whenever we perform any breaking change in the wire format!
const CURRENT_PACKET_VERSION_NUMBER: u8 = 7;
// TODO: ask @AP about the choice of below algorithms
/// Hashing algorithm used during hkdf for ephemeral shared key generation per sphinx packet payload.
+46 -32
View File
@@ -2,56 +2,70 @@
// SPDX-License-Identifier: Apache-2.0
use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter};
use thiserror::Error;
use crate::{PacketSize, CURRENT_PACKET_VERSION_NUMBER};
// wait, wait, but why are we starting with version 7?
// when packet header gets serialized, the following bytes (in that order) are put onto the wire:
// - packet_version (starting with v1.1.0)
// - packet_size indicator
// - packet_type
// it also just so happens that the only valid values for packet_size indicator include values 1-6
// therefore if we receive byte `7` (or larger than that) we'll know we received a versioned packet,
// otherwise we should treat it as legacy
/// Increment it whenever we perform any breaking change in the wire format!
pub const INITIAL_PACKET_VERSION_NUMBER: u8 = 7;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum PacketVersion {
// this will allow updated mixnodes to still understand packets from before the update
Legacy,
Versioned(u8),
pub const CURRENT_PACKET_VERSION_NUMBER: u8 = INITIAL_PACKET_VERSION_NUMBER;
pub const CURRENT_PACKET_VERSION: PacketVersion =
PacketVersion::unchecked(CURRENT_PACKET_VERSION_NUMBER);
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct PacketVersion(u8);
impl Display for PacketVersion {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
#[derive(Debug, Error)]
#[error("attempted to use legacy packet version")]
pub struct InvalidPacketVersion;
impl PacketVersion {
pub fn new() -> Self {
Self::new_versioned(CURRENT_PACKET_VERSION_NUMBER)
PacketVersion(CURRENT_PACKET_VERSION_NUMBER)
}
pub fn new_legacy() -> Self {
PacketVersion::Legacy
const fn unchecked(version: u8) -> PacketVersion {
PacketVersion(version)
}
pub fn new_versioned(version: u8) -> Self {
PacketVersion::Versioned(version)
}
pub fn is_legacy(&self) -> bool {
matches!(self, PacketVersion::Legacy)
}
pub fn as_u8(&self) -> Option<u8> {
match self {
PacketVersion::Legacy => None,
PacketVersion::Versioned(version) => Some(*version),
}
pub fn as_u8(&self) -> u8 {
(*self).into()
}
}
impl From<u8> for PacketVersion {
fn from(v: u8) -> Self {
match v {
n if n == PacketSize::RegularPacket as u8 => PacketVersion::Legacy,
n if n == PacketSize::AckPacket as u8 => PacketVersion::Legacy,
n if n == PacketSize::ExtendedPacket8 as u8 => PacketVersion::Legacy,
n if n == PacketSize::ExtendedPacket16 as u8 => PacketVersion::Legacy,
n if n == PacketSize::ExtendedPacket32 as u8 => PacketVersion::Legacy,
n => PacketVersion::Versioned(n),
impl TryFrom<u8> for PacketVersion {
type Error = InvalidPacketVersion;
fn try_from(value: u8) -> Result<Self, Self::Error> {
if value < INITIAL_PACKET_VERSION_NUMBER {
return Err(InvalidPacketVersion);
}
Ok(PacketVersion(value))
}
}
impl From<PacketVersion> for u8 {
fn from(packet_version: PacketVersion) -> Self {
packet_version.0
}
}
impl Default for PacketVersion {
fn default() -> Self {
PacketVersion::Versioned(CURRENT_PACKET_VERSION_NUMBER)
PacketVersion::new()
}
}
+5 -3
View File
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
use crate::chunking;
use nym_crypto::asymmetric::encryption;
use nym_crypto::asymmetric::x25519;
use nym_crypto::Digest;
use nym_sphinx_addressing::clients::Recipient;
use nym_sphinx_addressing::nodes::MAX_NODE_ADDRESS_UNPADDED_LEN;
@@ -113,7 +113,8 @@ impl NymMessage {
match self {
NymMessage::Plain(data) => data,
NymMessage::Repliable(repliable) => match repliable.content {
RepliableMessageContent::Data { message, .. } => message,
RepliableMessageContent::Data(content) => content.message,
RepliableMessageContent::DataV2(content) => content.message,
_ => Vec::new(),
},
NymMessage::Reply(reply) => match reply.content {
@@ -183,7 +184,7 @@ impl NymMessage {
// each plain or repliable packet attaches an ephemeral public key so that the recipient
// could perform diffie-hellman with its own keys followed by a kdf to re-derive
// the packet encryption key
NymMessage::Plain(_) | NymMessage::Repliable(_) => encryption::PUBLIC_KEY_SIZE,
NymMessage::Plain(_) | NymMessage::Repliable(_) => x25519::PUBLIC_KEY_SIZE,
// each reply attaches the digest of the encryption key so that the recipient could
// lookup correct key for decryption,
NymMessage::Reply(_) => ReplySurbKeyDigestAlgorithm::output_size(),
@@ -309,6 +310,7 @@ mod tests {
// a single variant for each repliable and reply is enough as they are more thoroughly tested
// internally
let repliable = NymMessage::new_repliable(RepliableMessage::new_data(
true,
vec![1, 2, 3, 4, 5],
[42u8; 16].into(),
vec![],
+19 -19
View File
@@ -4,7 +4,7 @@
use crate::message::{NymMessage, ACK_OVERHEAD, OUTFOX_ACK_OVERHEAD};
use crate::NymPayloadBuilder;
use log::debug;
use nym_crypto::asymmetric::encryption;
use nym_crypto::asymmetric::x25519;
use nym_crypto::Digest;
use nym_sphinx_acknowledgements::surb_ack::SurbAck;
use nym_sphinx_acknowledgements::AckKey;
@@ -51,29 +51,14 @@ impl From<PreparedFragment> for MixPacket {
pub trait FragmentPreparer {
type Rng: CryptoRng + Rng;
fn use_legacy_sphinx_format(&self) -> bool;
fn deterministic_route_selection(&self) -> bool;
fn rng(&mut self) -> &mut Self::Rng;
fn nonce(&self) -> i32;
fn average_packet_delay(&self) -> Duration;
fn average_ack_delay(&self) -> Duration;
fn generate_reply_surbs(
&mut self,
amount: usize,
topology: &NymRouteProvider,
reply_recipient: &Recipient,
) -> Result<Vec<ReplySurb>, NymTopologyError> {
let mut reply_surbs = Vec::with_capacity(amount);
let packet_delay = self.average_packet_delay();
for _ in 0..amount {
let reply_surb =
ReplySurb::construct(self.rng(), reply_recipient, packet_delay, topology)?;
reply_surbs.push(reply_surb)
}
Ok(reply_surbs)
}
fn generate_surb_ack(
&mut self,
recipient: &Recipient,
@@ -83,9 +68,11 @@ pub trait FragmentPreparer {
packet_type: PacketType,
) -> Result<SurbAck, NymTopologyError> {
let ack_delay = self.average_ack_delay();
let use_legacy_sphinx_format = self.use_legacy_sphinx_format();
SurbAck::construct(
self.rng(),
use_legacy_sphinx_format,
recipient,
ack_key,
fragment_id.to_bytes(),
@@ -203,7 +190,7 @@ pub trait FragmentPreparer {
let destination = packet_recipient.gateway();
monitoring::fragment_sent(&fragment, self.nonce(), destination);
let non_reply_overhead = encryption::PUBLIC_KEY_SIZE;
let non_reply_overhead = x25519::PUBLIC_KEY_SIZE;
let expected_plaintext = match packet_type {
PacketType::Outfox => {
fragment.serialized_size() + OUTFOX_ACK_OVERHEAD + non_reply_overhead
@@ -264,6 +251,7 @@ pub trait FragmentPreparer {
Some(packet_size.plaintext_size()),
)?,
PacketType::Mix => NymPacket::sphinx_build(
self.use_legacy_sphinx_format(),
packet_size.payload_size(),
packet_payload,
&route,
@@ -323,6 +311,10 @@ pub struct MessagePreparer<R> {
/// Average delay an acknowledgement packet is going to get delay at a single mixnode.
average_ack_delay: Duration,
/// Specify whether any constructed packets should use the legacy format,
/// where the payload keys are explicitly attached rather than using the seeds
use_legacy_sphinx_format: bool,
nonce: i32,
}
@@ -336,6 +328,7 @@ where
sender_address: Recipient,
average_packet_delay: Duration,
average_ack_delay: Duration,
use_legacy_sphinx_format: bool,
) -> Self {
let mut rng = rng;
let nonce = rng.gen();
@@ -345,6 +338,7 @@ where
sender_address,
average_packet_delay,
average_ack_delay,
use_legacy_sphinx_format,
nonce,
}
}
@@ -356,6 +350,7 @@ where
pub fn generate_reply_surbs(
&mut self,
use_legacy_reply_surb_format: bool,
amount: usize,
topology: &NymRouteProvider,
) -> Result<Vec<ReplySurb>, NymTopologyError> {
@@ -365,6 +360,7 @@ where
&mut self.rng,
&self.sender_address,
self.average_packet_delay,
use_legacy_reply_surb_format,
topology,
)?;
reply_surbs.push(reply_surb)
@@ -446,6 +442,10 @@ where
impl<R: CryptoRng + Rng> FragmentPreparer for MessagePreparer<R> {
type Rng = R;
fn use_legacy_sphinx_format(&self) -> bool {
self.use_legacy_sphinx_format
}
fn deterministic_route_selection(&self) -> bool {
self.deterministic_route_selection
}
+2 -2
View File
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
use nym_crypto::aes::cipher::{KeyIvInit, StreamCipher};
use nym_crypto::asymmetric::encryption;
use nym_crypto::asymmetric::x25519;
use nym_crypto::shared_key::new_ephemeral_shared_key;
use nym_crypto::symmetric::stream_cipher;
use nym_crypto::symmetric::stream_cipher::CipherKey;
@@ -67,7 +67,7 @@ impl NymPayloadBuilder {
pub fn build_regular<R>(
self,
rng: &mut R,
recipient_encryption_key: &encryption::PublicKey,
recipient_encryption_key: &x25519::PublicKey,
) -> Result<NymPayload, SurbAckRecoveryError>
where
R: RngCore + CryptoRng,
+8 -8
View File
@@ -3,7 +3,7 @@
use crate::message::{NymMessage, NymMessageError, PaddedMessage, PlainMessage};
use nym_crypto::aes::cipher::{KeyIvInit, StreamCipher};
use nym_crypto::asymmetric::encryption;
use nym_crypto::asymmetric::x25519;
use nym_crypto::shared_key::recompute_shared_key;
use nym_crypto::symmetric::stream_cipher;
use nym_crypto::symmetric::stream_cipher::CipherKey;
@@ -62,7 +62,7 @@ pub enum MessageRecoveryError {
NotEnoughBytesForEphemeralKey { provided: usize, required: usize },
#[error("Recovered remote x25519 public key is invalid - {0}")]
InvalidRemoteEphemeralKey(#[from] encryption::KeyRecoveryError),
InvalidRemoteEphemeralKey(#[from] x25519::KeyRecoveryError),
#[error("The reconstructed message was malformed - {source}")]
MalformedReconstructedMessage {
@@ -100,19 +100,19 @@ pub trait MessageReceiver {
fn recover_plaintext_from_regular_packet<'a>(
&self,
local_key: &encryption::PrivateKey,
local_key: &x25519::PrivateKey,
raw_enc_frag: &'a mut [u8],
) -> Result<&'a mut [u8], MessageRecoveryError> {
if raw_enc_frag.len() < encryption::PUBLIC_KEY_SIZE {
if raw_enc_frag.len() < x25519::PUBLIC_KEY_SIZE {
return Err(MessageRecoveryError::NotEnoughBytesForEphemeralKey {
provided: raw_enc_frag.len(),
required: encryption::PUBLIC_KEY_SIZE,
required: x25519::PUBLIC_KEY_SIZE,
});
}
// 1. recover remote encryption key
let remote_key_bytes = &raw_enc_frag[..encryption::PUBLIC_KEY_SIZE];
let remote_ephemeral_key = encryption::PublicKey::from_bytes(remote_key_bytes)?;
let remote_key_bytes = &raw_enc_frag[..x25519::PUBLIC_KEY_SIZE];
let remote_ephemeral_key = x25519::PublicKey::from_bytes(remote_key_bytes)?;
// 2. recompute shared encryption key
let encryption_key = recompute_shared_key::<PacketEncryptionAlgorithm, PacketHkdfAlgorithm>(
@@ -121,7 +121,7 @@ pub trait MessageReceiver {
);
// 3. decrypt fragment data
let fragment_ciphertext = &mut raw_enc_frag[encryption::PUBLIC_KEY_SIZE..];
let fragment_ciphertext = &mut raw_enc_frag[x25519::PUBLIC_KEY_SIZE..];
self.decrypt_raw_message::<PacketEncryptionAlgorithm>(
fragment_ciphertext,
+18 -7
View File
@@ -26,10 +26,13 @@ pub use sphinx_packet::{
crypto::{self, PrivateKey, PublicKey},
header::{self, delays, delays::Delay, ProcessedHeader, SphinxHeader, HEADER_SIZE},
packet::builder::DEFAULT_PAYLOAD_SIZE,
payload::{Payload, PAYLOAD_OVERHEAD_SIZE},
payload::{
key::{PayloadKey, PayloadKeySeed},
Payload, PAYLOAD_OVERHEAD_SIZE,
},
route::{Destination, DestinationAddressBytes, Node, NodeAddressBytes, SURBIdentifier},
surb::{SURBMaterial, SURB},
version::Version,
version::*,
Error as SphinxError, ProcessedPacket, ProcessedPacketData,
};
@@ -84,17 +87,25 @@ impl fmt::Debug for NymPacket {
impl NymPacket {
#[cfg(feature = "sphinx")]
pub fn sphinx_build<M: AsRef<[u8]>>(
use_legacy_sphinx_format: bool,
size: usize,
message: M,
route: &[Node],
destination: &Destination,
delays: &[Delay],
) -> Result<NymPacket, NymPacketError> {
Ok(NymPacket::Sphinx(
SphinxPacketBuilder::new()
.with_payload_size(size)
.build_packet(message, route, destination, delays)?,
))
let mut builder = SphinxPacketBuilder::new().with_payload_size(size);
if use_legacy_sphinx_format {
builder = builder.with_version(X25519_WITH_EXPLICIT_PAYLOAD_KEYS_VERSION)
};
Ok(NymPacket::Sphinx(builder.build_packet(
message,
route,
destination,
delays,
)?))
}
#[cfg(feature = "sphinx")]
pub fn sphinx_from_bytes(bytes: &[u8]) -> Result<NymPacket, NymPacketError> {
+1 -1
View File
@@ -1,4 +1,4 @@
use nym_crypto::asymmetric::identity::{PrivateKey, PublicKey, Signature};
use nym_crypto::asymmetric::ed25519::{PrivateKey, PublicKey, Signature};
use nym_mixnet_contract_common::NodeId;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
+3 -3
View File
@@ -5,7 +5,7 @@ use crate::error::VerlocError;
use crate::measurements::packet::{EchoPacket, ReplyPacket};
use bytes::{BufMut, BytesMut};
use futures::StreamExt;
use nym_crypto::asymmetric::identity;
use nym_crypto::asymmetric::ed25519;
use nym_task::ShutdownToken;
use std::net::SocketAddr;
use std::sync::Arc;
@@ -25,7 +25,7 @@ pub struct PacketListener {
impl PacketListener {
pub fn new(
address: SocketAddr,
identity: Arc<identity::KeyPair>,
identity: Arc<ed25519::KeyPair>,
shutdown_token: ShutdownToken,
) -> Self {
PacketListener {
@@ -75,7 +75,7 @@ impl PacketListener {
}
struct ConnectionHandler {
identity: Arc<identity::KeyPair>,
identity: Arc<ed25519::KeyPair>,
}
impl ConnectionHandler {
+2 -2
View File
@@ -7,7 +7,7 @@ use crate::measurements::{Config, PacketListener, PacketSender};
use crate::models::VerlocNodeResult;
use futures::stream::FuturesUnordered;
use futures::StreamExt;
use nym_crypto::asymmetric::identity;
use nym_crypto::asymmetric::ed25519;
use nym_task::ShutdownToken;
use nym_validator_client::models::NymNodeDescription;
use nym_validator_client::NymApiClient;
@@ -30,7 +30,7 @@ pub struct VerlocMeasurer {
impl VerlocMeasurer {
pub fn new(
config: Config,
identity: Arc<identity::KeyPair>,
identity: Arc<ed25519::KeyPair>,
shutdown_token: ShutdownToken,
) -> Self {
VerlocMeasurer {
+10 -1
View File
@@ -181,6 +181,14 @@ pub struct TrafficWasm {
/// Controls whether the sent sphinx packet use the NON-DEFAULT bigger size.
pub use_extended_packet_size: bool,
/// Specify whether any constructed sphinx packets should use the legacy format,
/// where the payload keys are explicitly attached rather than using the seeds
/// this affects any forward packets, acks and reply surbs
/// this flag should remain disabled until sufficient number of nodes on the network has upgraded
/// and support updated format.
/// in the case of reply surbs, the recipient must also understand the new encoding
pub use_legacy_sphinx_format: bool,
/// Controls whether the sent packets should use outfox as opposed to the default sphinx.
pub use_outfox: bool,
}
@@ -214,6 +222,7 @@ impl From<TrafficWasm> for ConfigTraffic {
.disable_main_poisson_packet_distribution,
primary_packet_size: PacketSize::RegularPacket,
secondary_packet_size: use_extended_packet_size,
use_legacy_sphinx_format: traffic.use_legacy_sphinx_format,
packet_type,
}
}
@@ -229,6 +238,7 @@ impl From<ConfigTraffic> for TrafficWasm {
maximum_number_of_retransmissions: traffic.maximum_number_of_retransmissions,
disable_main_poisson_packet_distribution: traffic
.disable_main_poisson_packet_distribution,
use_legacy_sphinx_format: traffic.use_legacy_sphinx_format,
use_extended_packet_size: traffic.secondary_packet_size.is_some(),
use_outfox: traffic.packet_type == PacketType::Outfox,
}
@@ -423,7 +433,6 @@ impl From<TopologyWasm> for ConfigTopology {
max_startup_gateway_waiting_period: Duration::from_millis(
topology.max_startup_gateway_waiting_period_ms as u64,
),
topology_structure: Default::default(),
minimum_mixnode_performance: topology.minimum_mixnode_performance,
minimum_gateway_performance: topology.minimum_gateway_performance,
use_extended_topology: topology.use_extended_topology,
@@ -109,6 +109,15 @@ pub struct TrafficWasmOverride {
#[tsify(optional)]
pub use_extended_packet_size: Option<bool>,
/// Specify whether any constructed sphinx packets should use the legacy format,
/// where the payload keys are explicitly attached rather than using the seeds
/// this affects any forward packets, acks and reply surbs
/// this flag should remain disabled until sufficient number of nodes on the network has upgraded
/// and support updated format.
/// in the case of reply surbs, the recipient must also understand the new encoding
#[tsify(optional)]
pub use_legacy_sphinx_format: Option<bool>,
/// Controls whether the sent packets should use outfox as opposed to the default sphinx.
#[tsify(optional)]
pub use_outfox: Option<bool>,
@@ -132,6 +141,9 @@ impl From<TrafficWasmOverride> for TrafficWasm {
disable_main_poisson_packet_distribution: value
.disable_main_poisson_packet_distribution
.unwrap_or(def.disable_main_poisson_packet_distribution),
use_legacy_sphinx_format: value
.use_legacy_sphinx_format
.unwrap_or(def.use_legacy_sphinx_format),
use_extended_packet_size: value
.use_extended_packet_size
.unwrap_or(def.use_extended_packet_size),
+1 -1
View File
@@ -5,7 +5,7 @@ use crate::storage::wasm_client_traits::WasmClientStorageError;
use crate::topology::WasmTopologyError;
use nym_client_core::client::base_client::storage::gateways_storage::BadGateway;
use nym_client_core::error::ClientCoreError;
use nym_crypto::asymmetric::identity::Ed25519RecoveryError;
use nym_crypto::asymmetric::ed25519::Ed25519RecoveryError;
use nym_gateway_client::error::GatewayClientError;
use nym_sphinx::addressing::clients::RecipientFormattingError;
use nym_sphinx::anonymous_replies::requests::InvalidAnonymousSenderTagRepresentation;
@@ -4,7 +4,7 @@
use crate::storage::types::WasmRawRegisteredGateway;
use async_trait::async_trait;
use nym_client_core::client::base_client::storage::gateways_storage::RawActiveGateway;
use nym_crypto::asymmetric::{encryption, identity};
use nym_crypto::asymmetric::{ed25519, x25519};
use nym_sphinx_acknowledgements::AckKey;
use std::error::Error;
use thiserror::Error;
@@ -60,7 +60,7 @@ pub trait WasmClientStorage: BaseWasmStorage {
async fn may_read_identity_keypair(
&self,
) -> Result<Option<identity::KeyPair>, <Self as WasmClientStorage>::StorageError> {
) -> Result<Option<ed25519::KeyPair>, <Self as WasmClientStorage>::StorageError> {
self.read_value(
v1::KEYS_STORE,
JsValue::from_str(v1::ED25519_IDENTITY_KEYPAIR),
@@ -71,7 +71,7 @@ pub trait WasmClientStorage: BaseWasmStorage {
async fn may_read_encryption_keypair(
&self,
) -> Result<Option<encryption::KeyPair>, <Self as WasmClientStorage>::StorageError> {
) -> Result<Option<x25519::KeyPair>, <Self as WasmClientStorage>::StorageError> {
self.read_value(
v1::KEYS_STORE,
JsValue::from_str(v1::X25519_ENCRYPTION_KEYPAIR),
@@ -90,7 +90,7 @@ pub trait WasmClientStorage: BaseWasmStorage {
async fn must_read_identity_keypair(
&self,
) -> Result<identity::KeyPair, <Self as WasmClientStorage>::StorageError> {
) -> Result<ed25519::KeyPair, <Self as WasmClientStorage>::StorageError> {
self.may_read_identity_keypair()
.await?
.ok_or(WasmClientStorageError::CryptoKeyNotInStorage {
@@ -101,7 +101,7 @@ pub trait WasmClientStorage: BaseWasmStorage {
async fn must_read_encryption_keypair(
&self,
) -> Result<encryption::KeyPair, <Self as WasmClientStorage>::StorageError> {
) -> Result<x25519::KeyPair, <Self as WasmClientStorage>::StorageError> {
self.may_read_encryption_keypair()
.await?
.ok_or(WasmClientStorageError::CryptoKeyNotInStorage {
@@ -130,7 +130,7 @@ pub trait WasmClientStorage: BaseWasmStorage {
async fn store_identity_keypair(
&self,
keypair: &identity::KeyPair,
keypair: &ed25519::KeyPair,
) -> Result<(), <Self as WasmClientStorage>::StorageError> {
self.store_value(
v1::KEYS_STORE,
@@ -143,7 +143,7 @@ pub trait WasmClientStorage: BaseWasmStorage {
async fn store_encryption_keypair(
&self,
keypair: &encryption::KeyPair,
keypair: &x25519::KeyPair,
) -> Result<(), <Self as WasmClientStorage>::StorageError> {
self.store_value(
v1::KEYS_STORE,
+1 -1
View File
@@ -7,7 +7,7 @@
// #![warn(clippy::unwrap_used)]
use defguard_wireguard_rs::WGApi;
use nym_crypto::asymmetric::encryption::KeyPair;
use nym_crypto::asymmetric::x25519::KeyPair;
use nym_wireguard_types::Config;
use peer_controller::PeerControlRequest;
use std::sync::Arc;
@@ -8,7 +8,7 @@ use crate::support::helpers::{
use cosmwasm_std::{coins, Addr, Coin, Decimal, Timestamp};
use cw_multi_test::{App, AppBuilder, Executor};
use nym_contracts_common::signing::{ContractMessageContent, MessageSignature, Nonce};
use nym_crypto::asymmetric::identity;
use nym_crypto::asymmetric::ed25519;
use nym_mixnet_contract_common::nym_node::{EpochAssignmentResponse, Role, RolesMetadataResponse};
use nym_mixnet_contract_common::reward_params::{NodeRewardingParameters, Performance};
use nym_mixnet_contract_common::{
@@ -376,9 +376,9 @@ impl TestSetup {
)
.unwrap();
let keypair = identity::KeyPair::new(&mut self.rng);
let keypair = ed25519::KeyPair::new(&mut self.rng);
let identity_key = keypair.public_key().to_base58_string();
let legit_sphinx_keys = nym_crypto::asymmetric::encryption::KeyPair::new(&mut self.rng);
let legit_sphinx_keys = nym_crypto::asymmetric::x25519::KeyPair::new(&mut self.rng);
let mixnode = MixNode {
identity_key,
@@ -724,8 +724,8 @@ pub mod tests {
let mut test = TestSetup::new();
let env = test.env();
let keypair1 = nym_crypto::asymmetric::identity::KeyPair::new(&mut test.rng);
let keypair2 = nym_crypto::asymmetric::identity::KeyPair::new(&mut test.rng);
let keypair1 = nym_crypto::asymmetric::ed25519::KeyPair::new(&mut test.rng);
let keypair2 = nym_crypto::asymmetric::ed25519::KeyPair::new(&mut test.rng);
let cost_params = fixtures::node_cost_params_fixture();
let mixnode1 = MixNode {
@@ -733,7 +733,7 @@ pub mod tests {
mix_port: 1234,
verloc_port: 1234,
http_api_port: 1234,
sphinx_key: nym_crypto::asymmetric::encryption::KeyPair::new(&mut test.rng)
sphinx_key: nym_crypto::asymmetric::x25519::KeyPair::new(&mut test.rng)
.public_key()
.to_base58_string(),
identity_key: keypair1.public_key().to_base58_string(),
@@ -742,7 +742,7 @@ pub mod tests {
// change identity but reuse sphinx key
let mut mixnode2 = mixnode1.clone();
mixnode2.sphinx_key = nym_crypto::asymmetric::encryption::KeyPair::new(&mut test.rng)
mixnode2.sphinx_key = nym_crypto::asymmetric::x25519::KeyPair::new(&mut test.rng)
.public_key()
.to_base58_string();

Some files were not shown because too many files have changed in this diff Show More