Compare commits

..

3 Commits

Author SHA1 Message Date
Merve 5313acd537 Update CHANGELOG.md 2026-02-10 14:10:03 +03:00
merve 8c4cacb23c changelog: add parmigiano release notes 2026-02-10 13:37:10 +03:00
Quinn cee27b1479 docs typos fixed 2026-01-24 13:57:14 +03:00
45 changed files with 795 additions and 855 deletions
+403 -1
View File
@@ -2,7 +2,409 @@
Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [2026.3-parmigiano] (2026-02-11)
- chore: disable LP on parmigiano branch ([#6422])
- bugfix: revert faulty mixnet-based registration changes from LP ([#6420])
- bugfix: registration client fallback handling for LP ([#6419])
- bugfix: unify LP and Authenticator peer registration and IP allocation ([#6412])
- bugfix: expose Wireguard PSK for vpn client ([#6411])
- bugfix: make LP timeouts configurable ([#6409])
- chore: include LP x25519 key in node description ([#6408])
- bugfix: use Send-safe RNG ([#6404])
- bugfix: use local KEM key instead of x25519 for KKT exchange ([#6402])
- improve: LP gateway probe CLI and behavior ([#6400])
- feature: negotiate and use LP protocol version ([#6399])
- bugfix: use correct reserved bytes when parsing LpHeader ([#6398])
- bugfix: share IP allocation across LP components ([#6395])
- feature: hex-encode LP key digests ([#6394])
- test: add socks5 test to gateway-probe ([#6393])
- chore: refactor LP gateway probe file structure ([#6391])
- chore: reduce HttpClientError size to satisfy clippy ([#6390])
- feature: two-step dVPN registration via LP ([#6386])
- chore: add extra configured nym api url to env ([#6382])
- feature: inject dVPN PSK after LP registration ([#6378])
- feature: include signing key digests in LP responses ([#6373])
- feature: reuse Noise x25519 key for LP KTT ([#6372])
- bugfix: topology fallback during epoch transitions ([#6363])
- feature: NS API socks5 support ([#6361])
- feature: dynamically select required KEM key hash for LP ([#6358])
- bugfix: fix KKT integration in LP client-node flow ([#6357])
- bugfix: LP mixnet registration fixes and packet kind tagging ([#6356])
- feature: announce KEM key hashes on LP endpoints ([#6349])
- revert: faulty drop changes ([#6346])
- chore: small LP QoL and cleanup changes ([#6340])
- feature: apply configured API URLs via env ([#6337])
- chore: take reserved bytes directly from LP header ([#6336])
- chore: x25519 / ed25519 cleanup in LP ([#6335])
- feature: encrypted KKT support in LP ([#6331])
- bugfix: reject packets with incompatible LP versions ([#6326])
- refactor: standardise LP serialisation format ([#6324])
- build(deps): upgrade def_guard_wireguard to v0.8.0 ([#6315])
- chore: crates.io publishing preparation v2 ([#6270])
[#6422]: https://github.com/nymtech/nym/pull/6422
[#6420]: https://github.com/nymtech/nym/pull/6420
[#6419]: https://github.com/nymtech/nym/pull/6419
[#6412]: https://github.com/nymtech/nym/pull/6412
[#6411]: https://github.com/nymtech/nym/pull/6411
[#6409]: https://github.com/nymtech/nym/pull/6409
[#6408]: https://github.com/nymtech/nym/pull/6408
[#6404]: https://github.com/nymtech/nym/pull/6404
[#6402]: https://github.com/nymtech/nym/pull/6402
[#6400]: https://github.com/nymtech/nym/pull/6400
[#6399]: https://github.com/nymtech/nym/pull/6399
[#6398]: https://github.com/nymtech/nym/pull/6398
[#6395]: https://github.com/nymtech/nym/pull/6395
[#6394]: https://github.com/nymtech/nym/pull/6394
[#6393]: https://github.com/nymtech/nym/pull/6393
[#6391]: https://github.com/nymtech/nym/pull/6391
[#6390]: https://github.com/nymtech/nym/pull/6390
[#6386]: https://github.com/nymtech/nym/pull/6386
[#6382]: https://github.com/nymtech/nym/pull/6382
[#6378]: https://github.com/nymtech/nym/pull/6378
[#6373]: https://github.com/nymtech/nym/pull/6373
[#6372]: https://github.com/nymtech/nym/pull/6372
[#6363]: https://github.com/nymtech/nym/pull/6363
[#6361]: https://github.com/nymtech/nym/pull/6361
[#6358]: https://github.com/nymtech/nym/pull/6358
[#6357]: https://github.com/nymtech/nym/pull/6357
[#6356]: https://github.com/nymtech/nym/pull/6356
[#6349]: https://github.com/nymtech/nym/pull/6349
[#6346]: https://github.com/nymtech/nym/pull/6346
[#6340]: https://github.com/nymtech/nym/pull/6340
[#6337]: https://github.com/nymtech/nym/pull/6337
[#6336]: https://github.com/nymtech/nym/pull/6336
[#6335]: https://github.com/nymtech/nym/pull/6335
[#6331]: https://github.com/nymtech/nym/pull/6331
[#6326]: https://github.com/nymtech/nym/pull/6326
[#6324]: https://github.com/nymtech/nym/pull/6324
[#6315]: https://github.com/nymtech/nym/pull/6315
[#6270]: https://github.com/nymtech/nym/pull/6270
## [2026.2-oscypek] (2026-01-27)
- bugfix: downgrade gateway protocol to clients proposed version ([#6377])
- bugfix: ack fix ([#6364])
- Cherry pick/api urls oscypek ([#6348])
- Update nix to v0.30.1 ([#6316])
- Deriving Serialize for GatewayData ([#6314])
- chore: remove repetitive words in comment ([#6313])
- [bugfix] Sqlite transaction escalation was causing errors ([#6299])
- DNS static table pre-resolve ([#6297])
- Add Copy+Clone to nym_api_provider::Config ([#6296])
- [chore] clippy fixes and use fixed rust version from REQUIRED_RUSTC_VERSION ([#6295])
- build(deps): bump SonarSource/sonarqube-scan-action from 6 to 7 ([#6294])
- build(deps): bump mikefarah/yq from 4.49.2 to 4.50.1 ([#6293])
- build(deps): bump actions/upload-artifact from 5 to 6 ([#6292])
- build(deps): bump actions/download-artifact from 6 to 7 ([#6291])
- build(deps): bump js-yaml from 3.14.1 to 3.14.2 in /documentation/docs ([#6290])
- build(deps): bump next from 15.4.9 to 15.4.10 in /nym-node-status-api/nym-node-status-ui ([#6289])
- build(deps): bump next from 14.2.33 to 14.2.35 ([#6288])
- LP Registration + Telescoping + Gateway Probe Localnet Mode ([#6286])
- build(deps): bump next from 15.5.7 to 15.5.9 in /documentation/docs ([#6285])
- build(deps): bump next from 15.4.7 to 15.4.9 in /nym-node-status-api/nym-node-status-ui ([#6284])
- Minor DNS improvements ([#6283])
- HTTP client without default features ([#6281])
- DNS: reduce number of attempts ([#6278])
- [bugfix] use proper mixing delay instead of poisson delay in cover traffic ([#6269])
- build(deps): bump node-forge from 1.3.1 to 1.3.3 in /wasm/zknym-lib/internal-dev ([#6261])
- build(deps-dev): bump node-forge from 1.3.1 to 1.3.3 in /wasm/mix-fetch/internal-dev ([#6260])
- build(deps-dev): bump node-forge from 1.3.1 to 1.3.2 in /wasm/client/internal-dev ([#6251])
- build(deps): bump node-forge from 1.3.1 to 1.3.2 in /nym-credential-proxy/vpn-api-lib-wasm/internal-dev ([#6250])
- [Feature] Fallback gateway listener and remove legacy key support ([#6249])
- build(deps-dev): bump node-forge from 1.3.0 to 1.3.2 in /clients/native/examples/js-examples/websocket ([#6248])
- build(deps): bump node-forge from 1.3.1 to 1.3.2 ([#6246])
- build(deps): bump pnpm/action-setup from 4.1.0 to 4.2.0 ([#6245])
- build(deps): bump actions/download-artifact from 5 to 6 ([#6244])
- build(deps): bump actions/checkout from 4 to 6 ([#6243])
- build(deps): bump mikefarah/yq from 4.48.1 to 4.49.2 ([#6242])
- build(deps): bump actions/upload-artifact from 4 to 5 ([#6241])
- fix: fix assertion ([#6238])
- Initial changes to support extra configurable parameters and to print… ([#6237])
- Data Observatory ([#6172])
[#6377]: https://github.com/nymtech/nym/pull/6377
[#6364]: https://github.com/nymtech/nym/pull/6364
[#6348]: https://github.com/nymtech/nym/pull/6348
[#6316]: https://github.com/nymtech/nym/pull/6316
[#6314]: https://github.com/nymtech/nym/pull/6314
[#6313]: https://github.com/nymtech/nym/pull/6313
[#6299]: https://github.com/nymtech/nym/pull/6299
[#6297]: https://github.com/nymtech/nym/pull/6297
[#6296]: https://github.com/nymtech/nym/pull/6296
[#6295]: https://github.com/nymtech/nym/pull/6295
[#6294]: https://github.com/nymtech/nym/pull/6294
[#6293]: https://github.com/nymtech/nym/pull/6293
[#6292]: https://github.com/nymtech/nym/pull/6292
[#6291]: https://github.com/nymtech/nym/pull/6291
[#6290]: https://github.com/nymtech/nym/pull/6290
[#6289]: https://github.com/nymtech/nym/pull/6289
[#6288]: https://github.com/nymtech/nym/pull/6288
[#6286]: https://github.com/nymtech/nym/pull/6286
[#6285]: https://github.com/nymtech/nym/pull/6285
[#6284]: https://github.com/nymtech/nym/pull/6284
[#6283]: https://github.com/nymtech/nym/pull/6283
[#6281]: https://github.com/nymtech/nym/pull/6281
[#6278]: https://github.com/nymtech/nym/pull/6278
[#6269]: https://github.com/nymtech/nym/pull/6269
[#6261]: https://github.com/nymtech/nym/pull/6261
[#6260]: https://github.com/nymtech/nym/pull/6260
[#6251]: https://github.com/nymtech/nym/pull/6251
[#6250]: https://github.com/nymtech/nym/pull/6250
[#6249]: https://github.com/nymtech/nym/pull/6249
[#6248]: https://github.com/nymtech/nym/pull/6248
[#6246]: https://github.com/nymtech/nym/pull/6246
[#6245]: https://github.com/nymtech/nym/pull/6245
[#6244]: https://github.com/nymtech/nym/pull/6244
[#6243]: https://github.com/nymtech/nym/pull/6243
[#6242]: https://github.com/nymtech/nym/pull/6242
[#6241]: https://github.com/nymtech/nym/pull/6241
[#6238]: https://github.com/nymtech/nym/pull/6238
[#6237]: https://github.com/nymtech/nym/pull/6237
[#6172]: https://github.com/nymtech/nym/pull/6172
## [2026.2-oscypek] (2026-01-27)
- bugfix: downgrade gateway protocol to clients proposed version ([#6377])
- bugfix: ack fix ([#6364])
- Cherry pick/api urls oscypek ([#6348])
- Update nix to v0.30.1 ([#6316])
- Deriving Serialize for GatewayData ([#6314])
- chore: remove repetitive words in comment ([#6313])
- [bugfix] Sqlite transaction escalation was causing errors ([#6299])
- DNS static table pre-resolve ([#6297])
- Add Copy+Clone to nym_api_provider::Config ([#6296])
- [chore] clippy fixes and use fixed rust version from REQUIRED_RUSTC_VERSION ([#6295])
- build(deps): bump SonarSource/sonarqube-scan-action from 6 to 7 ([#6294])
- build(deps): bump mikefarah/yq from 4.49.2 to 4.50.1 ([#6293])
- build(deps): bump actions/upload-artifact from 5 to 6 ([#6292])
- build(deps): bump actions/download-artifact from 6 to 7 ([#6291])
- build(deps): bump js-yaml from 3.14.1 to 3.14.2 in /documentation/docs ([#6290])
- build(deps): bump next from 15.4.9 to 15.4.10 in /nym-node-status-api/nym-node-status-ui ([#6289])
- build(deps): bump next from 14.2.33 to 14.2.35 ([#6288])
- LP Registration + Telescoping + Gateway Probe Localnet Mode ([#6286])
- build(deps): bump next from 15.5.7 to 15.5.9 in /documentation/docs ([#6285])
- build(deps): bump next from 15.4.7 to 15.4.9 in /nym-node-status-api/nym-node-status-ui ([#6284])
- Minor DNS improvements ([#6283])
- HTTP client without default features ([#6281])
- DNS: reduce number of attempts ([#6278])
- [bugfix] use proper mixing delay instead of poisson delay in cover traffic ([#6269])
- build(deps): bump node-forge from 1.3.1 to 1.3.3 in /wasm/zknym-lib/internal-dev ([#6261])
- build(deps-dev): bump node-forge from 1.3.1 to 1.3.3 in /wasm/mix-fetch/internal-dev ([#6260])
- build(deps-dev): bump node-forge from 1.3.1 to 1.3.2 in /wasm/client/internal-dev ([#6251])
- build(deps): bump node-forge from 1.3.1 to 1.3.2 in /nym-credential-proxy/vpn-api-lib-wasm/internal-dev ([#6250])
- [Feature] Fallback gateway listener and remove legacy key support ([#6249])
- build(deps-dev): bump node-forge from 1.3.0 to 1.3.2 in /clients/native/examples/js-examples/websocket ([#6248])
- build(deps): bump node-forge from 1.3.1 to 1.3.2 ([#6246])
- build(deps): bump pnpm/action-setup from 4.1.0 to 4.2.0 ([#6245])
- build(deps): bump actions/download-artifact from 5 to 6 ([#6244])
- build(deps): bump actions/checkout from 4 to 6 ([#6243])
- build(deps): bump mikefarah/yq from 4.48.1 to 4.49.2 ([#6242])
- build(deps): bump actions/upload-artifact from 4 to 5 ([#6241])
- fix: fix assertion ([#6238])
- Initial changes to support extra configurable parameters and to print… ([#6237])
- Data Observatory ([#6172])
[#6377]: https://github.com/nymtech/nym/pull/6377
[#6364]: https://github.com/nymtech/nym/pull/6364
[#6348]: https://github.com/nymtech/nym/pull/6348
[#6316]: https://github.com/nymtech/nym/pull/6316
[#6314]: https://github.com/nymtech/nym/pull/6314
[#6313]: https://github.com/nymtech/nym/pull/6313
[#6299]: https://github.com/nymtech/nym/pull/6299
[#6297]: https://github.com/nymtech/nym/pull/6297
[#6296]: https://github.com/nymtech/nym/pull/6296
[#6295]: https://github.com/nymtech/nym/pull/6295
[#6294]: https://github.com/nymtech/nym/pull/6294
[#6293]: https://github.com/nymtech/nym/pull/6293
[#6292]: https://github.com/nymtech/nym/pull/6292
[#6291]: https://github.com/nymtech/nym/pull/6291
[#6290]: https://github.com/nymtech/nym/pull/6290
[#6289]: https://github.com/nymtech/nym/pull/6289
[#6288]: https://github.com/nymtech/nym/pull/6288
[#6286]: https://github.com/nymtech/nym/pull/6286
[#6285]: https://github.com/nymtech/nym/pull/6285
[#6284]: https://github.com/nymtech/nym/pull/6284
[#6283]: https://github.com/nymtech/nym/pull/6283
[#6281]: https://github.com/nymtech/nym/pull/6281
[#6278]: https://github.com/nymtech/nym/pull/6278
[#6269]: https://github.com/nymtech/nym/pull/6269
[#6261]: https://github.com/nymtech/nym/pull/6261
[#6260]: https://github.com/nymtech/nym/pull/6260
[#6251]: https://github.com/nymtech/nym/pull/6251
[#6250]: https://github.com/nymtech/nym/pull/6250
[#6249]: https://github.com/nymtech/nym/pull/6249
[#6248]: https://github.com/nymtech/nym/pull/6248
[#6246]: https://github.com/nymtech/nym/pull/6246
[#6245]: https://github.com/nymtech/nym/pull/6245
[#6244]: https://github.com/nymtech/nym/pull/6244
[#6243]: https://github.com/nymtech/nym/pull/6243
[#6242]: https://github.com/nymtech/nym/pull/6242
[#6241]: https://github.com/nymtech/nym/pull/6241
[#6238]: https://github.com/nymtech/nym/pull/6238
[#6237]: https://github.com/nymtech/nym/pull/6237
[#6172]: https://github.com/nymtech/nym/pull/6172
## [2026.1-niolo] (2026-01-13)
- bugfix: mozzarella -> niolo config migration ([#6259])
- chore: remove run DKG migration ([#6253])
- bugfix: reexposed 'derive_extended_private_key' ([#6247])
- Bump js-yaml from 3.14.1 to 3.14.2 in /sdk/typescript/codegen/contract-clients ([#6231])
- Statistics API v2 ([#6227])
- Bump golang.org/x/crypto from 0.39.0 to 0.45.0 in /nym-gateway-probe/netstack_ping ([#6220])
- Update chain registry link ([#6219])
- Bump glob from 10.3.4 to 10.5.0 in /documentation/scripts/post-process ([#6216])
- Bump js-yaml from 4.1.0 to 4.1.1 in /sdk/typescript/tests/integration-tests/mix-fetch ([#6215])
- gateway-probe fixes for run-local ([#6212])
- chore: updated default endpoint for retrieving attestation.json ([#6207])
- chore: remove support for legacy mixnode within the performance contract ([#6205])
- feat: upgrade mode: VPN adjustments ([#6189])
- Bump min-document from 2.19.0 to 2.19.1 ([#6181])
- Bump next from 15.4.1 to 15.4.7 in /nym-node-status-api/nym-node-status-ui ([#6180])
- feat: merge intermediate upgrade mode changes ([#6174])
- Add weighted scoring to NS API ([#6144])
- build(deps): bump mikefarah/yq from 4.47.1 to 4.48.1 ([#6107])
- build(deps): bump SonarSource/sonarqube-scan-action from 5 to 6 in /.github/workflows ([#6068])
- build(deps): bump tar-fs from 3.0.9 to 3.1.1 in /sdk/typescript/tests/integration-tests/mix-fetch ([#6063])
- build(deps): bump ammonia from 4.1.1 to 4.1.2 ([#6057])
- build(deps): bump tower-http from 0.5.2 to 0.6.6 ([#6030])
- build(deps): bump actions/setup-go from 5 to 6 ([#6013])
- build(deps): bump next from 14.2.28 to 14.2.32 ([#5996])
- build(deps): bump tracing-subscriber from 0.3.19 to 0.3.20 ([#5993])
- build(deps): bump actions/upload-pages-artifact from 3 to 4 ([#5992])
[#6259]: https://github.com/nymtech/nym/pull/6259
[#6253]: https://github.com/nymtech/nym/pull/6253
[#6247]: https://github.com/nymtech/nym/pull/6247
[#6231]: https://github.com/nymtech/nym/pull/6231
[#6227]: https://github.com/nymtech/nym/pull/6227
[#6220]: https://github.com/nymtech/nym/pull/6220
[#6219]: https://github.com/nymtech/nym/pull/6219
[#6216]: https://github.com/nymtech/nym/pull/6216
[#6215]: https://github.com/nymtech/nym/pull/6215
[#6212]: https://github.com/nymtech/nym/pull/6212
[#6207]: https://github.com/nymtech/nym/pull/6207
[#6205]: https://github.com/nymtech/nym/pull/6205
[#6189]: https://github.com/nymtech/nym/pull/6189
[#6181]: https://github.com/nymtech/nym/pull/6181
[#6180]: https://github.com/nymtech/nym/pull/6180
[#6174]: https://github.com/nymtech/nym/pull/6174
[#6144]: https://github.com/nymtech/nym/pull/6144
[#6107]: https://github.com/nymtech/nym/pull/6107
[#6068]: https://github.com/nymtech/nym/pull/6068
[#6063]: https://github.com/nymtech/nym/pull/6063
[#6057]: https://github.com/nymtech/nym/pull/6057
[#6030]: https://github.com/nymtech/nym/pull/6030
[#6013]: https://github.com/nymtech/nym/pull/6013
[#5996]: https://github.com/nymtech/nym/pull/5996
[#5993]: https://github.com/nymtech/nym/pull/5993
[#5992]: https://github.com/nymtech/nym/pull/5992
## [2025.21-mozzarella] (2025-11-25)
- [bugfix] Tunnel not waiting on MixnetClient to shut down cleanly ([#6225])
- bugfix: fix credential proxy upgrade mode attestation url arg ([#6202])
- HTTP API resilience enable & domain rotation conditions ([#6200])
- Remove debug feature from http-macro spec in gateway probe ([#6195])
- DNS relibility and troubleshooting ([#6179])
- [bugfix] Distinguish authenticator errors by credential spent ([#6176])
- Typescript SDK 1.4.1 ([#6146])
- Enable URL rotation and retries for mixnet gateway init ([#6126])
- Feature/credential proxy jwt ([#5957])
[#6225]: https://github.com/nymtech/nym/pull/6225
[#6202]: https://github.com/nymtech/nym/pull/6202
[#6200]: https://github.com/nymtech/nym/pull/6200
[#6195]: https://github.com/nymtech/nym/pull/6195
[#6179]: https://github.com/nymtech/nym/pull/6179
[#6176]: https://github.com/nymtech/nym/pull/6176
[#6146]: https://github.com/nymtech/nym/pull/6146
[#6126]: https://github.com/nymtech/nym/pull/6126
[#5957]: https://github.com/nymtech/nym/pull/5957
## [2025.20-leerdammer] (2025-11-12)
## [2026.3-parmigiano] (2026-02-11)
- chore: disable LP on parmigiano branch ([#6422])
- bugfix: revert faulty mixnet-based registration changes from LP ([#6420])
- bugfix: registration client fallback handling for LP ([#6419])
- bugfix: unify LP and Authenticator peer registration and IP allocation ([#6412])
- bugfix: expose Wireguard PSK for vpn client ([#6411])
- bugfix: make LP timeouts configurable ([#6409])
- chore: include LP x25519 key in node description ([#6408])
- bugfix: use Send-safe RNG ([#6404])
- bugfix: use local KEM key instead of x25519 for KKT exchange ([#6402])
- improve: LP gateway probe CLI and behavior ([#6400])
- feature: negotiate and use LP protocol version ([#6399])
- bugfix: use correct reserved bytes when parsing LpHeader ([#6398])
- bugfix: share IP allocation across LP components ([#6395])
- feature: hex-encode LP key digests ([#6394])
- test: add socks5 test to gateway-probe ([#6393])
- chore: refactor LP gateway probe file structure ([#6391])
- chore: reduce HttpClientError size to satisfy clippy ([#6390])
- feature: two-step dVPN registration via LP ([#6386])
- chore: add extra configured nym api url to env ([#6382])
- feature: inject dVPN PSK after LP registration ([#6378])
- feature: include signing key digests in LP responses ([#6373])
- feature: reuse Noise x25519 key for LP KTT ([#6372])
- bugfix: topology fallback during epoch transitions ([#6363])
- feature: NS API socks5 support ([#6361])
- feature: dynamically select required KEM key hash for LP ([#6358])
- bugfix: fix KKT integration in LP client-node flow ([#6357])
- bugfix: LP mixnet registration fixes and packet kind tagging ([#6356])
- feature: announce KEM key hashes on LP endpoints ([#6349])
- revert: faulty drop changes ([#6346])
- chore: small LP QoL and cleanup changes ([#6340])
- feature: apply configured API URLs via env ([#6337])
- chore: take reserved bytes directly from LP header ([#6336])
- chore: x25519 / ed25519 cleanup in LP ([#6335])
- feature: encrypted KKT support in LP ([#6331])
- bugfix: reject packets with incompatible LP versions ([#6326])
- refactor: standardise LP serialisation format ([#6324])
- build(deps): upgrade def_guard_wireguard to v0.8.0 ([#6315])
- chore: crates.io publishing preparation v2 ([#6270])
[#6422]: https://github.com/nymtech/nym/pull/6422
[#6420]: https://github.com/nymtech/nym/pull/6420
[#6419]: https://github.com/nymtech/nym/pull/6419
[#6412]: https://github.com/nymtech/nym/pull/6412
[#6411]: https://github.com/nymtech/nym/pull/6411
[#6409]: https://github.com/nymtech/nym/pull/6409
[#6408]: https://github.com/nymtech/nym/pull/6408
[#6404]: https://github.com/nymtech/nym/pull/6404
[#6402]: https://github.com/nymtech/nym/pull/6402
[#6400]: https://github.com/nymtech/nym/pull/6400
[#6399]: https://github.com/nymtech/nym/pull/6399
[#6398]: https://github.com/nymtech/nym/pull/6398
[#6395]: https://github.com/nymtech/nym/pull/6395
[#6394]: https://github.com/nymtech/nym/pull/6394
[#6393]: https://github.com/nymtech/nym/pull/6393
[#6391]: https://github.com/nymtech/nym/pull/6391
[#6390]: https://github.com/nymtech/nym/pull/6390
[#6386]: https://github.com/nymtech/nym/pull/6386
[#6382]: https://github.com/nymtech/nym/pull/6382
[#6378]: https://github.com/nymtech/nym/pull/6378
[#6373]: https://github.com/nymtech/nym/pull/6373
[#6372]: https://github.com/nymtech/nym/pull/6372
[#6363]: https://github.com/nymtech/nym/pull/6363
[#6361]: https://github.com/nymtech/nym/pull/6361
[#6358]: https://github.com/nymtech/nym/pull/6358
[#6357]: https://github.com/nymtech/nym/pull/6357
[#6356]: https://github.com/nymtech/nym/pull/6356
[#6349]: https://github.com/nymtech/nym/pull/6349
[#6346]: https://github.com/nymtech/nym/pull/6346
[#6340]: https://github.com/nymtech/nym/pull/6340
[#6337]: https://github.com/nymtech/nym/pull/6337
[#6336]: https://github.com/nymtech/nym/pull/6336
[#6335]: https://github.com/nymtech/nym/pull/6335
[#6331]: https://github.com/nymtech/nym/pull/6331
[#6326]: https://github.com/nymtech/nym/pull/6326
[#6324]: https://github.com/nymtech/nym/pull/6324
[#6315]: https://github.com/nymtech/nym/pull/6315
[#6270]: https://github.com/nymtech/nym/pull/6270
## [2026.2-oscypek] (2026-01-27)
Generated
+2 -2
View File
@@ -5417,7 +5417,6 @@ dependencies = [
"nym-crypto",
"nym-ecash-signer-check-types",
"nym-ecash-time",
"nym-kkt-ciphersuite",
"nym-mixnet-contract-common",
"nym-network-defaults",
"nym-node-requests",
@@ -6475,7 +6474,6 @@ dependencies = [
"nym-http-api-client-macro",
"nym-ip-packet-client",
"nym-ip-packet-requests",
"nym-kkt-ciphersuite",
"nym-lp",
"nym-mixnet-contract-common",
"nym-network-defaults",
@@ -7525,6 +7523,8 @@ dependencies = [
"nym-test-utils",
"nym-wireguard-types",
"serde",
"time",
"tokio-util",
]
[[package]]
+3 -4
View File
@@ -432,7 +432,6 @@ nym-http-api-client = { version = "1.20.1", path = "common/http-api-client" }
nym-http-api-client-macro = { version = "1.20.1", path = "common/http-api-client-macro" }
nym-http-api-common = { version = "1.20.1", path = "common/http-api-common", default-features = false }
nym-id = { version = "1.20.1", path = "common/nym-id" }
nym-kkt-ciphersuite = { path = "common/nym-kkt-ciphersuite" }
nym-ip-packet-client = { version = "1.20.1", path = "nym-ip-packet-client" }
nym-ip-packet-requests = { version = "1.20.1", path = "common/ip-packet-requests" }
nym-metrics = { version = "1.20.1", path = "common/nym-metrics" }
@@ -483,9 +482,9 @@ nym-vesting-contract-common = { version = "1.20.1", path = "common/cosmwasm-smar
nym-verloc = { version = "1.20.1", path = "common/verloc" }
nym-wireguard = { version = "1.20.1", path = "common/wireguard" }
nym-wireguard-types = { version = "1.20.1", path = "common/wireguard-types" }
nym-wireguard-private-metadata-shared = { version = "1.20.1", path = "common/wireguard-private-metadata/shared" }
nym-wireguard-private-metadata-client = { version = "1.20.1", path = "common/wireguard-private-metadata/client" }
nym-wireguard-private-metadata-server = { version = "1.20.1", path = "common/wireguard-private-metadata/server" }
nym-wireguard-private-metadata-shared = { version = "1.20.1", path = "common/wireguard-private-metadata/shared" }
nym-wireguard-private-metadata-client = { version = "1.20.1", path = "common/wireguard-private-metadata/client" }
nym-wireguard-private-metadata-server = { version = "1.20.1", path = "common/wireguard-private-metadata/server" }
nym-sqlx-pool-guard = { version = "1.2.0", path = "nym-sqlx-pool-guard" }
nym-wasm-client-core = { version = "1.20.1", path = "common/wasm/client-core" }
nym-wasm-storage = { version = "1.20.1", path = "common/wasm/storage" }
@@ -1,7 +0,0 @@
/*
* Copyright 2026 - Nym Technologies SA <contact@nymtech.net>
* SPDX-License-Identifier: Apache-2.0
*/
ALTER TABLE wireguard_peer
ADD COLUMN psk VARCHAR;
-17
View File
@@ -577,21 +577,4 @@ impl BandwidthGatewayStorage for GatewayStorage {
.await?;
Ok(())
}
/// Update the stored PSK of the wireguard peer.
///
/// # Arguments
///
/// * `public_key`: the unique public key of the wireguard peer.
/// * `psk`: the PSK of the wireguard peer.
async fn update_peer_psk(
&self,
public_key: &str,
psk: Option<&str>,
) -> Result<(), GatewayStorageError> {
self.wireguard_peer_manager
.update_peer_psk(public_key, psk)
.await?;
Ok(())
}
}
-8
View File
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: GPL-3.0-only
use crate::{error::GatewayStorageError, make_bincode_serializer};
use defguard_wireguard_rs::key::Key;
use nym_credentials_interface::{AvailableBandwidth, ClientTicket, CredentialSpendingData};
use nym_gateway_requests::shared_key::SharedSymmetricKey;
use sqlx::FromRow;
@@ -96,7 +95,6 @@ pub struct WireguardPeer {
pub public_key: String,
pub allowed_ips: Vec<u8>,
pub client_id: i64,
pub psk: Option<String>,
}
impl WireguardPeer {
@@ -112,7 +110,6 @@ impl WireguardPeer {
source,
})?,
client_id,
psk: value.preshared_key.map(|psk| psk.to_lower_hex()),
})
}
}
@@ -135,11 +132,6 @@ impl TryFrom<WireguardPeer> for defguard_wireguard_rs::host::Peer {
field_key: "allowed_ips",
source,
})?,
preshared_key: value
.psk
.map(|psk| Key::decode(&psk))
.transpose()
.map_err(|_| Self::Error::TypeConversion { field_key: "psk" })?,
..Default::default()
})
}
-23
View File
@@ -170,18 +170,6 @@ pub trait BandwidthGatewayStorage: dyn_clone::DynClone {
/// * `peer_public_key`: wireguard public key of the peer to be removed.
async fn remove_wireguard_peer(&self, peer_public_key: &str)
-> Result<(), GatewayStorageError>;
/// Update the stored PSK of the wireguard peer.
///
/// # Arguments
///
/// * `public_key`: the unique public key of the wireguard peer.
/// * `psk`: the PSK of the wireguard peer.
async fn update_peer_psk(
&self,
public_key: &str,
psk: Option<&str>,
) -> Result<(), GatewayStorageError>;
}
#[cfg(feature = "mock")]
@@ -519,16 +507,5 @@ pub mod mock {
self.write().await.wireguard_peers.remove(peer_public_key);
Ok(())
}
async fn update_peer_psk(
&self,
public_key: &str,
psk: Option<&str>,
) -> Result<(), GatewayStorageError> {
if let Some(peer) = self.write().await.wireguard_peers.get_mut(public_key) {
peer.psk = psk.map(|psk| psk.to_owned())
}
Ok(())
}
}
}
@@ -98,29 +98,4 @@ impl WgPeerManager {
.await?;
Ok(())
}
/// Update the stored PSK of the wireguard peer.
///
/// # Arguments
///
/// * `public_key`: the unique public key of the wireguard peer.
/// * `psk`: the PSK of the wireguard peer.
pub(crate) async fn update_peer_psk(
&self,
public_key: &str,
psk: Option<&str>,
) -> Result<(), sqlx::Error> {
sqlx::query!(
r#"
UPDATE wireguard_peer
SET psk = ?
WHERE public_key = ?
"#,
psk,
public_key,
)
.execute(&self.connection_pool)
.await?;
Ok(())
}
}
+39 -85
View File
@@ -5,7 +5,7 @@ use crate::error::KKTCiphersuiteError;
use num_enum::{IntoPrimitive, TryFromPrimitive};
use std::collections::HashMap;
use std::fmt::Display;
use strum_macros::{Display, EnumIter, EnumString};
use strum_macros::EnumIter;
pub mod error;
@@ -45,31 +45,14 @@ pub mod xwing {
pub const PUBLIC_KEY_LENGTH: usize = x25519::PUBLIC_KEY_LENGTH + ml_kem768::PUBLIC_KEY_LENGTH;
}
pub type KEMKeyDigests = KeyDigests;
pub type SigningKeyDigests = KeyDigests;
pub type KEMKeyDigests = HashMap<HashFunction, Vec<u8>>;
pub type KeyDigests = HashMap<HashFunction, Vec<u8>>;
#[derive(
Clone,
Copy,
PartialEq,
Eq,
Hash,
Debug,
IntoPrimitive,
TryFromPrimitive,
EnumIter,
EnumString,
Display,
)]
#[strum(ascii_case_insensitive)]
#[strum(serialize_all = "lowercase")]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, IntoPrimitive, TryFromPrimitive, EnumIter)]
#[repr(u8)]
pub enum HashFunction {
Blake3 = 0,
Shake256 = 1,
Shake128 = 2,
SHAKE256 = 1,
SHAKE128 = 2,
SHA256 = 3,
}
@@ -84,8 +67,8 @@ impl HashFunction {
hasher.finalize_xof().fill(&mut out);
hasher.reset();
}
HashFunction::Shake256 => libcrux_sha3::shake256_ema(&mut out, data.as_ref()),
HashFunction::Shake128 => libcrux_sha3::shake128_ema(&mut out, data.as_ref()),
HashFunction::SHAKE256 => libcrux_sha3::shake256_ema(&mut out, data.as_ref()),
HashFunction::SHAKE128 => libcrux_sha3::shake128_ema(&mut out, data.as_ref()),
HashFunction::SHA256 => libcrux_sha3::sha256_ema(&mut out, data.as_ref()),
}
@@ -93,6 +76,17 @@ impl HashFunction {
}
}
impl Display for HashFunction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
HashFunction::Blake3 => "blake3",
HashFunction::SHAKE128 => "shake128",
HashFunction::SHAKE256 => "shake256",
HashFunction::SHA256 => "sha256",
})
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, IntoPrimitive)]
#[repr(u8)]
pub enum HashLength {
@@ -149,21 +143,7 @@ impl HashLength {
}
}
#[derive(
Clone,
Copy,
PartialEq,
Eq,
Hash,
Debug,
IntoPrimitive,
TryFromPrimitive,
EnumIter,
EnumString,
Display,
)]
#[strum(ascii_case_insensitive)]
#[strum(serialize_all = "lowercase")]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, IntoPrimitive, TryFromPrimitive)]
#[repr(u8)]
pub enum SignatureScheme {
Ed25519 = 0,
@@ -192,21 +172,15 @@ impl SignatureScheme {
}
}
#[derive(
Clone,
Copy,
PartialEq,
Eq,
Hash,
Debug,
IntoPrimitive,
TryFromPrimitive,
EnumIter,
EnumString,
Display,
)]
#[strum(ascii_case_insensitive)]
#[strum(serialize_all = "lowercase")]
impl Display for SignatureScheme {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
SignatureScheme::Ed25519 => "ed25519",
})
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, IntoPrimitive, TryFromPrimitive)]
#[repr(u8)]
pub enum KEM {
XWing = 0,
@@ -226,6 +200,17 @@ impl KEM {
}
}
impl Display for KEM {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
KEM::MlKem768 => "mlkem768",
KEM::XWing => "xwing",
KEM::X25519 => "x25519",
KEM::McEliece => "mceliece",
})
}
}
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct Ciphersuite {
hash_function: HashFunction,
@@ -350,34 +335,3 @@ impl Display for Ciphersuite {
)
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::str::FromStr;
use strum::IntoEnumIterator;
#[test]
fn kem_display_consistency() {
for kem in KEM::iter() {
let display = format!("{kem}");
assert_eq!(kem, KEM::from_str(&display).unwrap());
}
}
#[test]
fn hash_function_display_consistency() {
for hash_fn in HashFunction::iter() {
let display = format!("{hash_fn}");
assert_eq!(hash_fn, HashFunction::from_str(&display).unwrap());
}
}
#[test]
fn signature_scheme_display_consistency() {
for scheme in SignatureScheme::iter() {
let display = format!("{scheme}");
assert_eq!(scheme, SignatureScheme::from_str(&display).unwrap());
}
}
}
+1 -1
View File
@@ -15,7 +15,7 @@ strum = { workspace = true }
# internal
nym-crypto = { path = "../crypto", features = ["asymmetric", "serde"] }
nym-kkt-ciphersuite = { workspace = true, features = ["digests"] }
nym-kkt-ciphersuite = { path = "../nym-kkt-ciphersuite", features = ["digests"] }
libcrux-kem = { git = "https://github.com/cryspen/libcrux" }
libcrux-ecdh = { git = "https://github.com/cryspen/libcrux", features = ["codec"] }
+2 -2
View File
@@ -54,8 +54,8 @@ pub fn kkt_benchmark(c: &mut Criterion) {
for hash_function in [
HashFunction::Blake3,
HashFunction::SHA256,
HashFunction::Shake128,
HashFunction::Shake256,
HashFunction::SHAKE128,
HashFunction::SHAKE256,
] {
let ciphersuite = Ciphersuite::resolve_ciphersuite(
kem,
+2 -2
View File
@@ -3,7 +3,7 @@ use std::collections::HashMap;
use classic_mceliece_rust::keypair_boxed;
use nym_kkt_ciphersuite::{DEFAULT_HASH_LEN, KeyDigests};
use nym_kkt_ciphersuite::{DEFAULT_HASH_LEN, KEMKeyDigests};
use rand::{CryptoRng, RngCore};
pub fn generate_keypair_ed25519<R>(
@@ -78,7 +78,7 @@ pub fn hash_key_bytes(
/// attempt to produce digests of the provided key using all known [HashFunction] with a default
/// hash length where variable output is available
pub fn produce_key_digests(key_bytes: &[u8]) -> KeyDigests {
pub fn produce_key_digests(key_bytes: &[u8]) -> KEMKeyDigests {
use strum::IntoEnumIterator;
let mut digests = HashMap::new();
for hash in HashFunction::iter() {
+4 -4
View File
@@ -48,8 +48,8 @@ mod test {
for hash_function in [
HashFunction::Blake3,
HashFunction::SHA256,
HashFunction::Shake128,
HashFunction::Shake256,
HashFunction::SHAKE128,
HashFunction::SHAKE256,
] {
let ciphersuite = Ciphersuite::resolve_ciphersuite(
kem,
@@ -254,8 +254,8 @@ mod test {
for hash_function in [
HashFunction::Blake3,
HashFunction::SHA256,
HashFunction::Shake128,
HashFunction::Shake256,
HashFunction::SHAKE128,
HashFunction::SHAKE256,
] {
let ciphersuite = Ciphersuite::resolve_ciphersuite(
kem,
+9 -23
View File
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
use nym_crypto::asymmetric::{ed25519, x25519};
use nym_kkt::ciphersuite::{KEM, KEMKeyDigests, SignatureScheme, SigningKeyDigests};
use nym_kkt::ciphersuite::{HashFunction, KEM};
use std::collections::HashMap;
use std::sync::Arc;
@@ -49,26 +49,18 @@ impl LpLocalPeer {
let expected_kem_key_digests = match &self.kem_psq {
None => HashMap::new(),
Some(kem_keys) => {
let hashes =
nym_kkt::key_utils::produce_key_digests(kem_keys.public_key().as_bytes());
let mut digests = HashMap::new();
digests.insert(
KEM::X25519,
nym_kkt::key_utils::produce_key_digests(kem_keys.public_key().as_bytes()),
);
digests.insert(KEM::X25519, hashes);
digests
}
};
let mut expected_signing_key_digests = HashMap::new();
expected_signing_key_digests.insert(
SignatureScheme::Ed25519,
nym_kkt::key_utils::produce_key_digests(self.ed25519.public_key().as_bytes()),
);
LpRemotePeer {
ed25519_public: *self.ed25519.public_key(),
x25519_public: *self.x25519.public_key(),
expected_kem_key_digests,
expected_signing_key_digests,
}
}
@@ -93,11 +85,8 @@ pub struct LpRemotePeer {
/// Remote X25519 public key (Noise static key)
pub(crate) x25519_public: x25519::PublicKey,
/// Expected digests of the remote's KEM key
pub(crate) expected_kem_key_digests: HashMap<KEM, KEMKeyDigests>,
/// Expected digests of the remote's signing key
pub(crate) expected_signing_key_digests: HashMap<SignatureScheme, SigningKeyDigests>,
/// Expected digest of the remote's KEM key
pub(crate) expected_kem_key_digests: HashMap<KEM, HashMap<HashFunction, Vec<u8>>>,
}
impl LpRemotePeer {
@@ -106,7 +95,6 @@ impl LpRemotePeer {
ed25519_public,
x25519_public,
expected_kem_key_digests: Default::default(),
expected_signing_key_digests: Default::default(),
}
}
@@ -119,13 +107,11 @@ impl LpRemotePeer {
}
#[must_use]
pub fn with_key_digests(
pub fn with_kem_key_digests(
mut self,
expected_kem_key_digests: HashMap<KEM, KEMKeyDigests>,
expected_signing_key_digests: HashMap<SignatureScheme, SigningKeyDigests>,
expected_kem_key_digests: HashMap<KEM, HashMap<HashFunction, Vec<u8>>>,
) -> Self {
self.expected_kem_key_digests = expected_kem_key_digests;
self.expected_signing_key_digests = expected_signing_key_digests;
self
}
}
+3 -1
View File
@@ -15,6 +15,7 @@ workspace = true
[dependencies]
bincode = { workspace = true }
serde = { workspace = true, features = ["derive"] }
tokio-util.workspace = true
nym-authenticator-requests = { workspace = true }
nym-credentials-interface = { workspace = true }
@@ -22,8 +23,9 @@ nym-crypto = { workspace = true }
nym-ip-packet-requests = { workspace = true }
nym-sphinx = { workspace = true }
nym-wireguard-types = { workspace = true }
nym-kkt-ciphersuite = { workspace = true }
nym-kkt-ciphersuite = { path = "../nym-kkt-ciphersuite" }
[dev-dependencies]
bincode.workspace = true
time.workspace = true
nym-test-utils = { workspace = true }
+16 -19
View File
@@ -1,50 +1,47 @@
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_authenticator_requests::AuthenticatorVersion;
use nym_crypto::asymmetric::x25519::serde_helpers::bs58_x25519_pubkey;
use nym_crypto::asymmetric::{ed25519, x25519};
use nym_ip_packet_requests::IpPair;
use nym_kkt_ciphersuite::{KEM, KEMKeyDigests, SignatureScheme};
use nym_sphinx::addressing::Recipient;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
use nym_authenticator_requests::AuthenticatorVersion;
use nym_crypto::asymmetric::x25519::{PublicKey, serde_helpers::bs58_x25519_pubkey};
use nym_ip_packet_requests::IpPair;
use nym_sphinx::addressing::{NodeIdentity, Recipient};
use serde::{Deserialize, Serialize};
mod lp_messages;
mod serialisation;
pub use lp_messages::{
LpDvpnRegistrationRequest, LpMixnetGatewayData, LpMixnetRegistrationRequest,
LpRegistrationData, LpRegistrationRequest, LpRegistrationResponse, RegistrationMode,
};
use nym_kkt_ciphersuite::{KEM, KEMKeyDigests};
pub use serialisation::BincodeError;
mod lp_messages;
mod serialisation;
#[derive(Debug, Clone)]
pub struct NymNodeInformation {
pub identity: ed25519::PublicKey,
pub struct NymNode {
pub identity: NodeIdentity,
pub ip_address: IpAddr,
pub ipr_address: Option<Recipient>,
pub authenticator_address: Option<Recipient>,
pub lp_data: Option<NymNodeLPInformation>,
pub lp_data: Option<LpData>,
pub version: AuthenticatorVersion,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct WireguardConfiguration {
pub struct GatewayData {
#[serde(with = "bs58_x25519_pubkey")]
pub public_key: x25519::PublicKey,
pub public_key: PublicKey,
pub endpoint: SocketAddr,
pub private_ipv4: Ipv4Addr,
pub private_ipv6: Ipv6Addr,
}
#[derive(Clone, Debug)]
pub struct NymNodeLPInformation {
pub struct LpData {
pub address: SocketAddr,
pub expected_kem_key_hashes: HashMap<KEM, KEMKeyDigests>,
pub expected_signing_key_hashes: HashMap<SignatureScheme, KEMKeyDigests>,
pub x25519: x25519::PublicKey,
}
#[derive(Clone, Copy, Debug)]
+7 -19
View File
@@ -3,10 +3,9 @@
//! LP (Lewes Protocol) registration message types shared between client and gateway.
use crate::WireguardConfiguration;
use crate::GatewayData;
use crate::serialisation::{BincodeError, BincodeOptions, lp_bincode_serializer};
use nym_credentials_interface::{CredentialSpendingData, TicketType};
use nym_crypto::aes::cipher::crypto_common::rand_core::{CryptoRng, RngCore};
use nym_crypto::asymmetric::ed25519;
use serde::{Deserialize, Serialize};
@@ -51,9 +50,6 @@ pub struct LpDvpnRegistrationRequest {
/// Ticket type for bandwidth allocation
pub ticket_type: TicketType,
/// Preshared key to be used for the connection
pub psk: [u8; 32],
}
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -98,7 +94,7 @@ pub struct LpRegistrationResponse {
/// Gateway configuration data for dVPN mode (WireGuard)
/// This matches what WireguardRegistrationResult expects
pub gateway_data: Option<WireguardConfiguration>,
pub gateway_data: Option<GatewayData>,
/// Gateway data for mixnet mode
///
@@ -112,25 +108,17 @@ pub struct LpRegistrationResponse {
impl LpRegistrationRequest {
/// Create a new dVPN registration request
pub fn new_dvpn<R>(
rng: &mut R,
pub fn new_dvpn(
wg_public_key: nym_wireguard_types::PeerPublicKey,
credential: CredentialSpendingData,
ticket_type: TicketType,
) -> Self
where
R: RngCore + CryptoRng,
{
let mut psk = [0u8; 32];
rng.fill_bytes(&mut psk);
) -> Self {
Self {
registration_data: LpRegistrationData::Dvpn {
data: Box::new(LpDvpnRegistrationRequest {
wg_public_key,
credential,
ticket_type,
psk,
}),
},
#[allow(clippy::expect_used)]
@@ -164,7 +152,7 @@ impl LpRegistrationRequest {
impl LpRegistrationResponse {
/// Create a success response with GatewayData (for dVPN mode)
pub fn success(allocated_bandwidth: i64, gateway_data: WireguardConfiguration) -> Self {
pub fn success(allocated_bandwidth: i64, gateway_data: GatewayData) -> Self {
Self {
success: true,
error: None,
@@ -214,10 +202,10 @@ mod tests {
use std::net::Ipv4Addr;
// ==================== Helper Functions ====================
fn create_test_gateway_data() -> WireguardConfiguration {
fn create_test_gateway_data() -> GatewayData {
use std::net::Ipv6Addr;
WireguardConfiguration {
GatewayData {
public_key: nym_crypto::asymmetric::x25519::PublicKey::from(
nym_sphinx::PublicKey::from([1u8; 32]),
),
+1 -5
View File
@@ -23,8 +23,4 @@ NYM_API=https://canary-api.performance.nymte.ch/api/
NYXD_WS=wss://rpc.canary-validator.performance.nymte.ch/websocket
NYM_VPN_API=https://nym-vpn-api-git-deploy-canary-nyx-network-staging.vercel.app/api/
UPGRADE_MODE_ATTESTER_ED25519_PUBKEY=U1NXToPYUTsh7pYPLcwXCXwcL6pGoLUou7fyAJrNz8b
UPGRADE_MODE_ATTESTATION_URL=http://upgrade-mode.performance.nymte.ch/.wellknown/canary/attestation.json
NYM_APIS=[{"url":"https://canary-api.performance.nymte.ch/api/","front_hosts":null},{"url":"https://nym-frontdoor.vercel.app/canary/nym-api/","front_hosts":["vercel.app","vercel.com"]}]
NYM_VPN_APIS=[{"url":"https://nym-vpn-api-git-deploy-canary-nyx-network-staging.vercel.app/api/","front_hosts":["vercel.app","vercel.com"]},{"url":"https://nym-frontdoor.vercel.app/canary/nym-vpn-api/","front_hosts":["vercel.app","vercel.com"]}]
UPGRADE_MODE_ATTESTER_ED25519_PUBKEY=U1NXToPYUTsh7pYPLcwXCXwcL6pGoLUou7fyAJrNz8b
+1 -5
View File
@@ -24,8 +24,4 @@ NYXD_WS=wss://rpc.sandbox.nymtech.net/websocket
NYM_API=https://sandbox-nym-api1.nymtech.net/api/
NYM_VPN_API=https://nym-vpn-api-git-deploy-sandbox-nyx-network-staging.vercel.app/api/
UPGRADE_MODE_ATTESTER_ED25519_PUBKEY=EGwzKXPrqStv8cHF68VT2LbQuEBGDPzhCAixScvybfem
UPGRADE_MODE_ATTESTATION_URL=http://upgrade-mode.performance.nymte.ch/.wellknown/sandbox/attestation.json
NYM_APIS=[{"url":"https://sandbox-nym-api1.nymtech.net/api/","front_hosts":null},{"url":"https://nym-frontdoor.vercel.app/sandbox/nym-api/","front_hosts":["vercel.app","vercel.com"]}]
NYM_VPN_APIS=[{"url":"https://nym-vpn-api-git-deploy-sandbox-nyx-network-staging.vercel.app/api/","front_hosts":["vercel.app","vercel.com"]},{"url":"https://nym-frontdoor.vercel.app/sandbox/nym-vpn-api/","front_hosts":["vercel.app","vercel.com"]}]
UPGRADE_MODE_ATTESTER_ED25519_PUBKEY=EGwzKXPrqStv8cHF68VT2LbQuEBGDPzhCAixScvybfem
@@ -497,7 +497,7 @@ impl<R, S> FreshHandler<R, S> {
Err(incompatible_err)
} else {
debug!("the client is using exactly the same (or older) protocol version as we are. We're good to continue!");
Ok(client_protocol_version)
Ok(CURRENT_PROTOCOL_VERSION)
}
}
+6 -33
View File
@@ -18,11 +18,10 @@ use nym_gateway_storage::models::PersistedBandwidth;
use nym_gateway_storage::traits::BandwidthGatewayStorage;
use nym_metrics::{add_histogram_obs, inc, inc_by};
use nym_registration_common::{
LpDvpnRegistrationRequest, LpMixnetGatewayData, LpMixnetRegistrationRequest,
LpRegistrationData, LpRegistrationRequest, LpRegistrationResponse, WireguardConfiguration,
GatewayData, LpDvpnRegistrationRequest, LpMixnetGatewayData, LpMixnetRegistrationRequest,
LpRegistrationData, LpRegistrationRequest, LpRegistrationResponse,
};
use nym_wireguard::PeerControlRequest;
use nym_wireguard_types::PeerPublicKey;
use std::sync::Arc;
use time::OffsetDateTime;
use tracing::*;
@@ -186,7 +185,7 @@ async fn check_existing_registration(
Some(LpRegistrationResponse::success(
bandwidth,
WireguardConfiguration {
GatewayData {
public_key: *wg_data.keypair().public_key(),
endpoint: wg_data.config().bind_address,
private_ipv4,
@@ -195,20 +194,6 @@ async fn check_existing_registration(
))
}
/// In the case of an already registered WG peer, update its PSK.
async fn update_peer_psk(
peer: PeerPublicKey,
psk: Key,
state: &LpHandlerState,
) -> Result<(), GatewayError> {
let encoded_psk = psk.to_lower_hex();
state
.storage
.update_peer_psk(&peer.to_string(), Some(&encoded_psk))
.await?;
Ok(())
}
async fn process_dvpn_registration(
request: Box<LpDvpnRegistrationRequest>,
state: &LpHandlerState,
@@ -221,13 +206,6 @@ async fn process_dvpn_registration(
// without wasting credentials
let wg_key_str = request.wg_public_key.to_string();
if let Some(existing_response) = check_existing_registration(&wg_key_str, state).await {
// TODO: this flow will be changed in subsequent PRs as it's wasting credentials regardless
if let Err(err) = update_peer_psk(request.wg_public_key, Key::new(request.psk), state).await
{
return LpRegistrationResponse::error(format!(
"WireGuard peer PSK update failed: {err}"
));
}
info!("LP dVPN re-registration for existing peer {wg_key_str} (idempotent)",);
inc!("lp_registration_dvpn_idempotent");
return existing_response;
@@ -237,7 +215,6 @@ async fn process_dvpn_registration(
let (gateway_data, client_id) = match register_wg_peer(
request.wg_public_key.inner().as_ref(),
request.ticket_type,
Key::new(request.psk),
state,
)
.await
@@ -372,9 +349,8 @@ pub async fn process_registration(
async fn register_wg_peer(
public_key_bytes: &[u8],
ticket_type: nym_credentials_interface::TicketType,
psk: Key,
state: &LpHandlerState,
) -> Result<(WireguardConfiguration, i64), GatewayError> {
) -> Result<(GatewayData, i64), GatewayError> {
let Some(wg_controller) = &state.wg_peer_controller else {
return Err(GatewayError::ServiceProviderNotRunning {
service: "WireGuard".to_string(),
@@ -398,10 +374,8 @@ async fn register_wg_peer(
let peer_key = Key::new(key_bytes);
// Allocate IPs from centralized pool managed by PeerController
let registration_data =
nym_wireguard::PeerRegistrationData::new(peer_key.clone()).with_preshared_key(psk);
let registration_data = nym_wireguard::PeerRegistrationData::new(peer_key.clone());
let psk = registration_data.preshared_key.clone();
// Request IP allocation from PeerController
let (tx, rx) = oneshot::channel();
wg_controller
@@ -441,7 +415,6 @@ async fn register_wg_peer(
format!("{client_ipv6}/128").parse()?,
];
peer.persistent_keepalive_interval = Some(25);
peer.preshared_key = psk;
// Store peer in database FIRST (before adding to controller)
// This ensures bandwidth storage exists when controller's generate_bandwidth_manager() is called
@@ -494,7 +467,7 @@ async fn register_wg_peer(
// Create GatewayData response (matching authenticator response format)
Ok((
WireguardConfiguration {
GatewayData {
public_key: gateway_pubkey,
endpoint: gateway_endpoint,
private_ipv4: client_ipv4,
+12 -10
View File
@@ -93,9 +93,6 @@ pub struct GatewayTasksBuilder {
/// ed25519 keypair used to assert one's identity.
identity_keypair: Arc<ed25519::KeyPair>,
/// x25519 keypair used within KTT exchange
x25519_keypair: Arc<x25519::KeyPair>,
/// x25519 (for now, to be changed into MlKem) keypair used for the PSQ derivation
kem_psq_keys: Arc<x25519::KeyPair>,
@@ -127,7 +124,6 @@ impl GatewayTasksBuilder {
pub fn new(
config: Config,
identity: Arc<ed25519::KeyPair>,
x25519: Arc<x25519::KeyPair>,
kem_psq_keys: Arc<x25519::KeyPair>,
storage: GatewayStorage,
mix_packet_sender: MixForwardingSender,
@@ -146,7 +142,6 @@ impl GatewayTasksBuilder {
wireguard_data: None,
user_agent,
identity_keypair: identity,
x25519_keypair: x25519,
kem_psq_keys,
storage,
mix_packet_sender,
@@ -336,14 +331,21 @@ impl GatewayTasksBuilder {
.as_ref()
.map(|wg_data| wg_data.inner.peer_tx().clone());
// We use standard RFC 7748 conversion to derive X25519 keys from Ed25519 identity keys.
// This allows callers to provide only Ed25519 keys (which they already have for signing/identity)
// without needing to manage separate X25519 keypairs.
//
// Security: Ed25519→X25519 conversion is cryptographically sound (RFC 7748).
// The derived X25519 keys are used for:
// - Noise protocol ephemeral DH
// - PSQ ECDH baseline security (pre-quantum)
let x25519_keys = Arc::new(self.identity_keypair.to_x25519());
let handler_state = lp_listener::LpHandlerState {
ecash_verifier: self.ecash_manager().await?,
storage: self.storage.clone(),
local_lp_peer: LpLocalPeer::new(
self.identity_keypair.clone(),
self.x25519_keypair.clone(),
)
.with_kem_psq_key(self.kem_psq_keys.clone()),
local_lp_peer: LpLocalPeer::new(self.identity_keypair.clone(), x25519_keys)
.with_kem_psq_key(self.kem_psq_keys.clone()),
metrics: self.metrics.clone(),
active_clients_store,
wg_peer_controller,
+3 -4
View File
@@ -392,6 +392,7 @@ mod tests {
client_data.base.peer.ed25519().clone(),
entry.base.peer.as_remote(),
entry.base.socket_addr,
client_data.base.socket_addr.ip(),
);
// 1. establish mock connection between client and gateway and retrieve gateway's handle
@@ -441,7 +442,6 @@ mod tests {
let gateway_identity = entry.base.peer.ed25519().public_key();
let registration_result = client
.register(
&mut client_rng,
&wg_keypair,
gateway_identity,
&client_data.ticket_provider,
@@ -483,6 +483,7 @@ mod tests {
client_data.base.peer.ed25519().clone(),
entry.base.peer.as_remote(),
entry.base.socket_addr,
client_data.base.socket_addr.ip(),
);
// 1. establish mock connection between client and gateway and retrieve gateway's handle
@@ -507,7 +508,6 @@ mod tests {
let gateway_identity = entry.base.peer.ed25519().public_key();
let registration_result = client
.register(
&mut client_rng,
&wg_keypair,
gateway_identity,
&client_data.ticket_provider,
@@ -544,6 +544,7 @@ mod tests {
client_data.base.peer.ed25519().clone(),
entry.base.peer.as_remote(),
entry.base.socket_addr,
client_data.base.socket_addr.ip(),
);
// START: ENTRY SETUP
@@ -648,7 +649,6 @@ mod tests {
let exit_registration_result = nested_session
.handshake_and_register(
&mut entry_client,
&mut client_rng,
&client_data.base.x25519_wg_keys,
exit.base.peer.ed25519().public_key(),
&client_data.ticket_provider,
@@ -660,7 +660,6 @@ mod tests {
// 14. complete registration with the entry
let entry_registration_result = entry_client
.register(
&mut client_rng,
&client_data.base.x25519_wg_keys,
entry.base.peer.ed25519().public_key(),
&client_data.ticket_provider,
+1 -1
View File
@@ -49,7 +49,7 @@ nym-noise-keys = { workspace = true }
nym-network-defaults = { workspace = true }
nym-ticketbooks-merkle = { workspace = true }
nym-ecash-signer-check-types = { workspace = true }
nym-kkt-ciphersuite = { workspace = true }
[dev-dependencies]
rand_chacha = { workspace = true }
@@ -8,7 +8,6 @@ use celes::Country;
use nym_crypto::asymmetric::ed25519::serde_helpers::bs58_ed25519_pubkey;
use nym_crypto::asymmetric::x25519::serde_helpers::bs58_x25519_pubkey;
use nym_crypto::asymmetric::{ed25519, x25519};
use nym_kkt_ciphersuite::{HashFunction, SignatureScheme, KEM};
use nym_network_defaults::{WG_METADATA_PORT, WG_TUNNEL_PORT};
use nym_noise_keys::VersionedNoiseKeyV1;
use schemars::JsonSchema;
@@ -212,20 +211,6 @@ pub struct LewesProtocolDetailsV1 {
/// Digests of the KEM keys available to this node alongside hashing algorithms used
/// for their computation.
pub kem_keys: HashMap<LPKEM, HashMap<LPHashFunction, Vec<u8>>>,
/// Digests of the signing keys available to this node alongside hashing algorithms used
/// for their computation.
pub signing_keys: HashMap<LPSignatureScheme, HashMap<LPHashFunction, Vec<u8>>>,
}
/// Convert map of digests from `nym_node_requests` types into `nym-api-requests` types
fn translate_digests(
digests: HashMap<nym_node_requests::api::v1::lewes_protocol::models::LPHashFunction, Vec<u8>>,
) -> HashMap<LPHashFunction, Vec<u8>> {
digests
.into_iter()
.map(|(hash_fn, digest)| (hash_fn.into(), digest))
.collect()
}
#[derive(
@@ -274,26 +259,6 @@ pub enum LPHashFunction {
Sha256,
}
#[derive(
Serialize,
Deserialize,
Debug,
Clone,
Copy,
JsonSchema,
Hash,
PartialEq,
Eq,
PartialOrd,
Display,
EnumString,
ToSchema,
)]
#[strum(serialize_all = "lowercase")]
pub enum LPSignatureScheme {
Ed25519,
}
impl From<nym_node_requests::api::v1::node::models::HostInformation> for HostInformationV1 {
fn from(value: nym_node_requests::api::v1::node::models::HostInformation) -> Self {
HostInformationV1 {
@@ -416,12 +381,15 @@ impl From<nym_node_requests::api::v1::lewes_protocol::models::LewesProtocol>
kem_keys: value
.kem_keys
.into_iter()
.map(|(kem, digests)| (kem.into(), translate_digests(digests)))
.collect(),
signing_keys: value
.signing_keys
.into_iter()
.map(|(scheme, digests)| (scheme.into(), translate_digests(digests)))
.map(|(kem, digests)| {
(
kem.into(),
digests
.into_iter()
.map(|(hash_fn, digest)| (hash_fn.into(), digest))
.collect(),
)
})
.collect(),
}
}
@@ -456,45 +424,3 @@ impl From<nym_node_requests::api::v1::lewes_protocol::models::LPHashFunction> fo
}
}
}
impl From<nym_node_requests::api::v1::lewes_protocol::models::LPSignatureScheme>
for LPSignatureScheme
{
fn from(value: nym_node_requests::api::v1::lewes_protocol::models::LPSignatureScheme) -> Self {
match value {
nym_node_requests::api::v1::lewes_protocol::models::LPSignatureScheme::Ed25519 => {
LPSignatureScheme::Ed25519
}
}
}
}
impl From<LPKEM> for KEM {
fn from(value: LPKEM) -> Self {
match value {
LPKEM::MlKem768 => KEM::MlKem768,
LPKEM::XWing => KEM::XWing,
LPKEM::X25519 => KEM::X25519,
LPKEM::McEliece => KEM::McEliece,
}
}
}
impl From<LPHashFunction> for HashFunction {
fn from(value: LPHashFunction) -> Self {
match value {
LPHashFunction::Blake3 => HashFunction::Blake3,
LPHashFunction::Shake128 => HashFunction::Shake128,
LPHashFunction::Shake256 => HashFunction::Shake256,
LPHashFunction::Sha256 => HashFunction::SHA256,
}
}
}
impl From<LPSignatureScheme> for SignatureScheme {
fn from(value: LPSignatureScheme) -> Self {
match value {
LPSignatureScheme::Ed25519 => SignatureScheme::Ed25519,
}
}
}
@@ -247,7 +247,7 @@ impl From<NymNodeDescriptionV1> for NymNodeDescriptionV2 {
#[cfg(test)]
pub fn mock_nym_node_description(seed: u64) -> NymNodeDescriptionV2 {
use crate::models::{LPHashFunction, LPSignatureScheme, LPKEM};
use crate::models::{LPHashFunction, LPKEM};
use nym_test_utils::helpers::{u64_seeded_rng, RngCore};
let mut rng = u64_seeded_rng(seed);
@@ -257,16 +257,11 @@ pub fn mock_nym_node_description(seed: u64) -> NymNodeDescriptionV2 {
// just reuse the same x25519 key for everything - this is just a data mock
let x25519 = x25519::KeyPair::new(&mut rng);
let mut kem_hashes_wrapper = std::collections::HashMap::new();
let mut signing_keys_hashes_wrapper = std::collections::HashMap::new();
let mut kem_hashes = std::collections::HashMap::new();
let mut signing_keys_hashes = std::collections::HashMap::new();
let mut hashes_wrapper = std::collections::HashMap::new();
let mut hashes = std::collections::HashMap::new();
kem_hashes.insert(LPHashFunction::Sha256, vec![(seed % 256) as u8; 32]);
kem_hashes_wrapper.insert(LPKEM::X25519, kem_hashes);
signing_keys_hashes.insert(LPHashFunction::Sha256, vec![(seed % 256) as u8; 32]);
signing_keys_hashes_wrapper.insert(LPSignatureScheme::Ed25519, signing_keys_hashes);
hashes.insert(LPHashFunction::Sha256, vec![(seed % 256) as u8; 32]);
hashes_wrapper.insert(LPKEM::X25519, hashes);
NymNodeDescriptionV2 {
node_id: rng.next_u32(),
@@ -337,8 +332,7 @@ pub fn mock_nym_node_description(seed: u64) -> NymNodeDescriptionV2 {
enabled: true,
control_port: 1234,
data_port: 2345,
kem_keys: kem_hashes_wrapper,
signing_keys: signing_keys_hashes_wrapper,
kem_keys: hashes_wrapper,
}),
mixnet_websockets: WebSocketsV2 {
ws_port: 9000,
+3 -3
View File
@@ -4,7 +4,7 @@
use nym_authenticator_requests::client_message::QueryMessageImpl;
use nym_bandwidth_controller::{BandwidthTicketProvider, DEFAULT_TICKETS_TO_SPEND};
use nym_crypto::asymmetric::x25519::KeyPair;
use nym_registration_common::WireguardConfiguration;
use nym_registration_common::GatewayData;
use std::net::{IpAddr, SocketAddr};
use std::sync::Arc;
use std::time::Duration;
@@ -261,7 +261,7 @@ impl AuthenticatorClient {
&mut self,
controller: &dyn BandwidthTicketProvider,
ticketbook_type: TicketType,
) -> std::result::Result<WireguardConfiguration, RegistrationError> {
) -> std::result::Result<GatewayData, RegistrationError> {
debug!("Registering with the wg gateway...");
let pub_key = self.peer_public_key();
@@ -348,7 +348,7 @@ impl AuthenticatorClient {
&self.ip_addr, &registered_data
);
let gateway_data = WireguardConfiguration {
let gateway_data = GatewayData {
public_key: registered_data.pub_key().inner().into(),
endpoint: SocketAddr::new(self.ip_addr, registered_data.wg_port()),
private_ipv4: registered_data.private_ips().ipv4,
-2
View File
@@ -65,8 +65,6 @@ nym-node-status-client = { path = "../nym-node-status-api/nym-node-status-client
nym-node-requests = { path = "../nym-node/nym-node-requests" }
nym-registration-client = { path = "../nym-registration-client" }
nym-lp = { path = "../common/nym-lp" }
nym-kkt-ciphersuite = { workspace = true }
nym-mixnet-contract-common = { path = "../common/cosmwasm-smart-contracts/mixnet-contract" }
nym-network-defaults = { path = "../common/network-defaults" }
nym-registration-common = { path = "../common/registration" }
+87 -81
View File
@@ -1,8 +1,14 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use std::{
net::{IpAddr, Ipv4Addr, Ipv6Addr},
sync::Arc,
time::Duration,
};
use crate::types::Entry;
use anyhow::bail;
use anyhow::{Context, bail};
use base64::{Engine as _, engine::general_purpose};
use bytes::BytesMut;
use clap::Args;
@@ -33,14 +39,7 @@ use nym_sdk::mixnet::{
NodeIdentity, Recipient, ReconstructedMessage, StoragePaths,
};
use rand::rngs::OsRng;
use std::collections::HashMap;
use std::net::SocketAddr;
use std::path::PathBuf;
use std::{
net::{IpAddr, Ipv4Addr, Ipv6Addr},
sync::Arc,
time::Duration,
};
use tokio::net::TcpStream;
use tokio_util::{codec::Decoder, sync::CancellationToken};
use tracing::*;
@@ -63,11 +62,8 @@ mod types;
use crate::bandwidth_helpers::{acquire_bandwidth, import_bandwidth};
use crate::nodes::{DirectoryNode, NymApiDirectory};
pub use mode::TestMode;
use nym_crypto::asymmetric::{ed25519, x25519};
use nym_kkt_ciphersuite::{KEM, KEMKeyDigests, SignatureScheme};
use nym_lp::peer::LpRemotePeer;
use nym_node_status_client::models::AttachedTicketMaterials;
use nym_registration_client::{LpRegistrationClient, NestedLpSession};
pub use types::{IpPingReplies, ProbeOutcome, ProbeResult};
#[derive(Args, Clone)]
@@ -160,24 +156,17 @@ pub struct TestedNodeDetails {
authenticator_address: Option<Recipient>,
authenticator_version: AuthenticatorVersion,
ip_address: Option<IpAddr>,
lp_data: Option<TestedNodeLpDetails>,
}
#[derive(Debug, Clone)]
pub struct TestedNodeLpDetails {
pub address: SocketAddr,
pub expected_kem_key_hashes: HashMap<KEM, KEMKeyDigests>,
pub expected_signing_key_hashes: HashMap<SignatureScheme, KEMKeyDigests>,
pub x25519: x25519::PublicKey,
lp_address: Option<std::net::SocketAddr>,
}
impl TestedNodeDetails {
/// Create from CLI args (localnet mode - no HTTP query needed)
pub fn from_cli(identity: NodeIdentity, lp_data: TestedNodeLpDetails) -> Self {
/// Only identity and LP address are required; other fields are None/default.
pub fn from_cli(identity: NodeIdentity, lp_address: std::net::SocketAddr) -> Self {
Self {
identity,
ip_address: Some(lp_data.address.ip()),
lp_data: Some(lp_data),
ip_address: Some(lp_address.ip()),
lp_address: Some(lp_address),
// These are None in localnet mode - only needed for mixnet/authenticator
exit_router_address: None,
authenticator_address: None,
@@ -187,7 +176,7 @@ impl TestedNodeDetails {
/// Check if this node has sufficient info for LP testing
pub fn can_test_lp(&self) -> bool {
self.lp_data.is_some()
self.lp_address.is_some()
}
/// Check if this node has sufficient info for mixnet testing
@@ -588,8 +577,11 @@ impl Probe {
}
// Check if node has LP address
let Some(lp_data) = node_info.lp_data else {
bail!("Gateway does not have LP data configured");
let (lp_address, ip_address) = match (node_info.lp_address, node_info.ip_address) {
(Some(lp_addr), Some(ip_addr)) => (lp_addr, ip_addr),
_ => {
bail!("Gateway does not have LP address configured");
}
};
info!("Testing LP registration for gateway {}", node_info.identity);
@@ -605,10 +597,15 @@ impl Probe {
);
// Run LP registration probe
let lp_outcome =
lp_registration_probe(node_info.identity, lp_data, &bw_controller, use_mock_ecash)
.await
.unwrap_or_default();
let lp_outcome = lp_registration_probe(
node_info.identity,
lp_address,
ip_address,
&bw_controller,
use_mock_ecash,
)
.await
.unwrap_or_default();
// Return result with only LP outcome
Ok(ProbeResult {
@@ -928,8 +925,10 @@ impl Probe {
};
// Test LP registration if node has LP address
let lp_outcome = if let Some(lp_data) = node_info.lp_data {
info!("Node has LP data, testing LP registration...");
let lp_outcome = if let (Some(lp_address), Some(ip_address)) =
(node_info.lp_address, node_info.ip_address)
{
info!("Node has LP address, testing LP registration...");
// Prepare bandwidth credential for LP registration
let config = nym_validator_client::nyxd::Config::try_from_nym_network_details(
@@ -942,10 +941,15 @@ impl Probe {
client,
);
let outcome =
lp_registration_probe(node_info.identity, lp_data, &bw_controller, use_mock_ecash)
.await
.unwrap_or_default();
let outcome = lp_registration_probe(
node_info.identity,
lp_address,
ip_address,
&bw_controller,
use_mock_ecash,
)
.await
.unwrap_or_default();
Some(outcome)
} else {
@@ -1077,16 +1081,10 @@ async fn wg_probe(
Ok(wg_outcome)
}
fn to_lp_remote_peer(identity: ed25519::PublicKey, data: TestedNodeLpDetails) -> LpRemotePeer {
LpRemotePeer::new(identity, data.x25519).with_key_digests(
data.expected_kem_key_hashes,
data.expected_signing_key_hashes,
)
}
async fn lp_registration_probe<St>(
gateway_identity: NodeIdentity,
gateway_lp_data: TestedNodeLpDetails,
gateway_lp_address: std::net::SocketAddr,
gateway_ip: IpAddr,
bandwidth_controller: &nym_bandwidth_controller::BandwidthController<
nym_validator_client::nyxd::NyxdClient<nym_validator_client::HttpRpcClient>,
St,
@@ -1100,10 +1098,10 @@ where
use nym_crypto::asymmetric::ed25519;
use nym_registration_client::LpRegistrationClient;
let lp_address = gateway_lp_data.address;
let peer = to_lp_remote_peer(gateway_identity, gateway_lp_data);
info!("Starting LP registration probe for gateway at {lp_address}",);
info!(
"Starting LP registration probe for gateway at {}",
gateway_lp_address
);
let mut lp_outcome = types::LpProbeResults::default();
@@ -1112,18 +1110,23 @@ where
let client_ed25519_keypair = std::sync::Arc::new(ed25519::KeyPair::new(&mut rng));
// Step 0: Derive X25519 keys from Ed25519 for the gateways
let gateway_x25519_key = gateway_identity
.to_x25519()
.context("failed to convert entry ed25519 key to x25519")?;
let peer = LpRemotePeer::new(gateway_identity, gateway_x25519_key);
// Create LP registration client (uses Ed25519 keys directly, derives X25519 internally)
let mut client = LpRegistrationClient::<TcpStream>::new_with_default_config(
client_ed25519_keypair,
peer,
lp_address,
gateway_lp_address,
gateway_ip,
);
// Step 1: Perform handshake (connection is implicit in packet-per-connection model)
// LpRegistrationClient uses packet-per-connection model - connect() is gone,
// connection is established during handshake and registration automatically.
info!("Performing LP handshake at {lp_address}...");
info!("Performing LP handshake at {}...", gateway_lp_address);
match client.perform_handshake().await {
Ok(_) => {
info!("LP handshake completed successfully");
@@ -1168,7 +1171,7 @@ where
);
match client
.register_with_credential(&mut rng, &wg_keypair, credential, ticket_type)
.register_with_credential(&wg_keypair, credential, ticket_type)
.await
{
Ok(data) => data,
@@ -1183,7 +1186,6 @@ where
info!("Using real bandwidth controller for LP registration");
match client
.register(
&mut rng,
&wg_keypair,
&gateway_ed25519_pubkey,
bandwidth_controller,
@@ -1243,38 +1245,49 @@ where
St: nym_sdk::mixnet::CredentialStorage + Clone + Send + Sync + 'static,
<St as nym_sdk::mixnet::CredentialStorage>::StorageError: Send + Sync,
{
// Validate that both gateways have required information
let entry_lp_data = entry_gateway
.lp_data
.clone()
.ok_or_else(|| anyhow::anyhow!("Entry gateway missing LP data"))?;
let exit_lp_data = exit_gateway
.lp_data
.clone()
.ok_or_else(|| anyhow::anyhow!("Exit gateway missing LP data"))?;
let entry_address = entry_lp_data.address;
let exit_address = exit_lp_data.address;
let entry_ip = entry_address.ip();
let exit_ip = exit_address.ip();
use nym_crypto::asymmetric::{ed25519, x25519};
use nym_registration_client::{LpRegistrationClient, NestedLpSession};
info!("Starting LP-based WireGuard probe (entry→exit via forwarding)");
let mut wg_outcome = WgProbeResults::default();
// Validate that both gateways have required information
let entry_lp_address = entry_gateway
.lp_address
.ok_or_else(|| anyhow::anyhow!("Entry gateway missing LP address"))?;
let exit_lp_address = exit_gateway
.lp_address
.ok_or_else(|| anyhow::anyhow!("Exit gateway missing LP address"))?;
let entry_ip = entry_gateway
.ip_address
.ok_or_else(|| anyhow::anyhow!("Entry gateway missing IP address"))?;
let exit_ip = exit_gateway
.ip_address
.ok_or_else(|| anyhow::anyhow!("Exit gateway missing IP address"))?;
// Generate Ed25519 keypairs for LP protocol
let mut rng = rand::thread_rng();
let entry_lp_keypair = Arc::new(ed25519::KeyPair::new(&mut rng));
let exit_lp_keypair = Arc::new(ed25519::KeyPair::new(&mut rng));
// Step 0: Derive X25519 keys from Ed25519 for the gateways
let entry_x25519_public = entry_gateway
.identity
.to_x25519()
.context("failed to convert entry ed25519 key to x25519")?;
let exit_x25519_public = exit_gateway
.identity
.to_x25519()
.context("failed to convert exit ed25519 key to x25519")?;
// Generate WireGuard keypairs for VPN registration
let entry_wg_keypair = x25519::KeyPair::new(&mut rng);
let exit_wg_keypair = x25519::KeyPair::new(&mut rng);
let entry_peer = to_lp_remote_peer(entry_gateway.identity, entry_lp_data);
let exit_peer = to_lp_remote_peer(exit_gateway.identity, exit_lp_data);
let entry_peer = LpRemotePeer::new(entry_gateway.identity, entry_x25519_public);
let exit_peer = LpRemotePeer::new(exit_gateway.identity, exit_x25519_public);
// STEP 1: Establish outer LP session with entry gateway
// LpRegistrationClient uses packet-per-connection model - connect() is gone,
@@ -1283,7 +1296,8 @@ where
let mut entry_client = LpRegistrationClient::<TcpStream>::new_with_default_config(
entry_lp_keypair,
entry_peer,
entry_address,
entry_lp_address,
entry_ip,
);
// Perform handshake with entry gateway (connection is implicit)
@@ -1296,7 +1310,7 @@ where
// STEP 2: Use nested session to register with exit gateway via forwarding
info!("Registering with exit gateway via entry forwarding...");
let mut nested_session =
NestedLpSession::new(exit_address.to_string(), exit_lp_keypair, exit_peer);
NestedLpSession::new(exit_lp_address.to_string(), exit_lp_keypair, exit_peer);
// Convert exit gateway identity to ed25519 public key for registration
let exit_gateway_pubkey = ed25519::PublicKey::from_bytes(&exit_gateway.identity.to_bytes())
@@ -1312,7 +1326,6 @@ where
match nested_session
.handshake_and_register_with_credential(
&mut entry_client,
&mut rng,
&exit_wg_keypair,
credential,
TicketType::V1WireguardExit,
@@ -1329,7 +1342,6 @@ where
match nested_session
.handshake_and_register(
&mut entry_client,
&mut rng,
&exit_wg_keypair,
&exit_gateway_pubkey,
bandwidth_controller,
@@ -1360,12 +1372,7 @@ where
TicketType::V1WireguardEntry,
);
match entry_client
.register_with_credential(
&mut rng,
&entry_wg_keypair,
credential,
TicketType::V1WireguardEntry,
)
.register_with_credential(&entry_wg_keypair, credential, TicketType::V1WireguardEntry)
.await
{
Ok(data) => data,
@@ -1377,7 +1384,6 @@ where
} else {
match entry_client
.register(
&mut rng,
&entry_wg_keypair,
&entry_gateway_pubkey,
bandwidth_controller,
+23 -49
View File
@@ -1,7 +1,7 @@
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::{TestedNodeDetails, TestedNodeLpDetails};
use crate::TestedNodeDetails;
use anyhow::{Context, anyhow, bail};
use nym_api_requests::models::{
AuthenticatorDetailsV2, DeclaredRolesV2, DescribedNodeTypeV2, HostInformationV2,
@@ -19,7 +19,6 @@ use nym_validator_client::client::NymApiClientExt;
use nym_validator_client::models::NymNodeDescriptionV2;
use rand::prelude::IteratorRandom;
use std::collections::HashMap;
use std::net::SocketAddr;
use std::time::Duration;
use time::OffsetDateTime;
use tracing::{debug, info, warn};
@@ -97,14 +96,16 @@ impl DirectoryNode {
}
pub fn to_testable_node(&self) -> anyhow::Result<TestedNodeDetails> {
let description = &self.described.description;
let exit_router_address = description
let exit_router_address = self
.described
.description
.ip_packet_router
.as_ref()
.map(|ipr| ipr.address.parse().context("malformed ipr address"))
.transpose()?;
let authenticator_address = description
let authenticator_address = self
.described
.description
.authenticator
.as_ref()
.map(|ipr| {
@@ -113,59 +114,32 @@ impl DirectoryNode {
.context("malformed authenticator address")
})
.transpose()?;
let authenticator_version =
AuthenticatorVersion::from(description.build_information.build_version.as_str());
let ip_address = description
let authenticator_version = AuthenticatorVersion::from(
self.described
.description
.build_information
.build_version
.as_str(),
);
let ip_address = self
.described
.description
.host_information
.ip_address
.first()
.copied()
.ok_or_else(|| anyhow!("no ip address known"))?;
.copied();
let lp_data = match (
description.lewes_protocol.clone(),
description.host_information.keys.x25519_versioned_noise,
) {
(Some(lp_data), Some(noise_key)) => Some(TestedNodeLpDetails {
address: SocketAddr::new(ip_address, lp_data.control_port),
expected_kem_key_hashes: lp_data
.kem_keys
.into_iter()
.map(|(kem, digests)| {
(
kem.into(),
digests
.into_iter()
.map(|(hash_fn, digest)| (hash_fn.into(), digest))
.collect(),
)
})
.collect(),
expected_signing_key_hashes: lp_data
.signing_keys
.into_iter()
.map(|(scheme, digests)| {
(
scheme.into(),
digests
.into_iter()
.map(|(hash_fn, digest)| (hash_fn.into(), digest))
.collect(),
)
})
.collect(),
x25519: noise_key.x25519_pubkey,
}),
_ => None,
};
// Derive LP address from gateway IP + default LP control port (41264)
// TODO: Update this when LP address is exposed in node description API
let lp_address = ip_address.map(|ip| std::net::SocketAddr::new(ip, 41264));
Ok(TestedNodeDetails {
identity: self.identity(),
exit_router_address,
authenticator_address,
authenticator_version,
ip_address: Some(ip_address),
lp_data,
ip_address,
lp_address,
})
}
}
+27 -114
View File
@@ -5,15 +5,11 @@ use anyhow::bail;
use clap::{Parser, Subcommand};
use nym_bin_common::bin_info;
use nym_config::defaults::setup_env;
use nym_crypto::asymmetric::{ed25519, x25519};
use nym_gateway_probe::nodes::{NymApiDirectory, query_gateway_by_ip};
use nym_gateway_probe::{
CredentialArgs, NetstackArgs, ProbeResult, TestMode, TestedNode, TestedNodeDetails,
TestedNodeLpDetails,
};
use nym_kkt_ciphersuite::{HashFunction, KEM};
use nym_sdk::mixnet::NodeIdentity;
use std::collections::HashMap;
use std::net::SocketAddr;
use std::path::Path;
use std::{path::PathBuf, sync::OnceLock};
@@ -50,70 +46,32 @@ struct CliArgs {
#[arg(long, global = true)]
gateway_ip: Option<String>,
// ##########
// ENTRY
// ##########
/// Ed25519 identity of the entry gateway (base58 encoded)
/// When provided, skips HTTP API query - use for localnet testing
#[arg(long, global = true)]
entry_gateway_identity: Option<String>,
/// x25519 key of the entry gateway used for KKT exchange (base58 encoded)
#[arg(long, global = true, requires = "entry_gateway_identity")]
entry_gateway_x25519_key: Option<String>,
/// expected kem type of the entry gateway used during KKT exchange
#[arg(long, global = true, requires = "entry_gateway_x25519_key")]
entry_gateway_kem_key_type: Option<String>,
/// expected hash function used for the entry gateway kem key digest
#[arg(long, global = true, requires = "entry_gateway_kem_key_type")]
entry_gateway_kem_key_hash_function: Option<String>,
/// expected entry gateway kem key digest (base58 encoded)
#[arg(long, global = true, requires = "entry_gateway_kem_key_hash_function")]
entry_gateway_kem_hey_hash_bs58: Option<String>,
/// LP listener address for entry gateway (e.g., "192.168.66.6:41264")
/// Used with --entry-gateway-identity for localnet mode
#[arg(long, global = true)]
entry_lp_address: Option<SocketAddr>,
// ##########
// EXIT
// ##########
/// The address of the exit gateway for LP forwarding tests (used with --test-lp-wg)
/// When specified, --gateway-ip becomes the entry gateway and this becomes the exit gateway
/// Supports formats: IP (192.168.66.5), IP:PORT (192.168.66.5:8080), HOST:PORT (localhost:30004)
#[arg(long, global = true)]
exit_gateway_ip: Option<String>,
/// Ed25519 identity of the entry gateway (base58 encoded)
/// When provided, skips HTTP API query - use for localnet testing
#[arg(long, global = true)]
entry_gateway_identity: Option<String>,
/// Ed25519 identity of the exit gateway (base58 encoded)
/// When provided, skips HTTP API query - use for localnet testing
#[arg(long, global = true)]
exit_gateway_identity: Option<String>,
/// x25519 key of the exit gateway used for KKT exchange (base58 encoded)
#[arg(long, global = true, requires = "exit_gateway_identity")]
exit_gateway_x25519_key: Option<String>,
/// expected kem type of the exit gateway used during KKT exchange
#[arg(long, global = true, requires = "exit_gateway_x25519_key")]
exit_gateway_kem_key_type: Option<String>,
/// expected hash function used for the exit gateway kem key digest
#[arg(long, global = true, requires = "exit_gateway_kem_key_type")]
exit_gateway_kem_key_hash_function: Option<String>,
/// expected exit gateway kem key digest (base58 encoded)
#[arg(long, global = true, requires = "exit_gateway_kem_key_hash_function")]
exit_gateway_kem_hey_hash_bs58: Option<String>,
/// LP listener address for entry gateway (e.g., "192.168.66.6:41264")
/// Used with --entry-gateway-identity for localnet mode
#[arg(long, global = true)]
entry_lp_address: Option<String>,
/// LP listener address for exit gateway (e.g., "172.18.0.5:41264")
/// This is the address the entry gateway uses to reach exit (for forwarding)
/// Used with --exit-gateway-identity for localnet mode
#[arg(long, global = true)]
exit_lp_address: Option<SocketAddr>,
exit_lp_address: Option<String>,
/// Default LP control port when deriving LP address from gateway IP
#[arg(long, global = true, default_value = "41264")]
@@ -244,10 +202,6 @@ fn mode_to_flags(mode: TestMode) -> (bool, bool, bool) {
}
}
#[allow(clippy::todo)]
#[allow(unreachable_code, unused)]
// ^^^^ // NOTE: to be changed by @SW
#[allow(clippy::unwrap_used)]
pub(crate) async fn run() -> anyhow::Result<ProbeResult> {
let args = CliArgs::parse();
if !args.no_log {
@@ -270,35 +224,21 @@ pub(crate) async fn run() -> anyhow::Result<ProbeResult> {
// 3. Directory mode: uses nym-api directory service
// Localnet mode: identity provided via CLI, skip HTTP queries entirely
if let Some(kem_key_digest) = &args.entry_gateway_kem_hey_hash_bs58 {
if let Some(entry_identity_str) = &args.entry_gateway_identity {
info!("Using localnet mode with CLI-provided gateway identity");
// SAFETY: if kem key digest is provided, all other LP data must also be present
// (enforced by clap)
let hash_fn: HashFunction = args
.entry_gateway_kem_key_hash_function
.as_ref()
.unwrap()
.parse()?;
let kem_type: KEM = args.entry_gateway_kem_key_type.as_ref().unwrap().parse()?;
let x25519_key: x25519::PublicKey =
args.entry_gateway_x25519_key.as_ref().unwrap().parse()?;
let identity: ed25519::PublicKey = args.entry_gateway_identity.as_ref().unwrap().parse()?;
let digest = bs58::decode(&kem_key_digest).into_vec()?;
let mut expected_kem_key_hashes = HashMap::new();
let mut digests = HashMap::new();
digests.insert(hash_fn, digest);
expected_kem_key_hashes.insert(kem_type, digests);
let entry_identity = NodeIdentity::from_base58_string(entry_identity_str)?;
// Entry LP address: explicit or derived from gateway_ip + lp_port
let entry_lp_addr: SocketAddr = if let Some(lp_addr) = args.entry_lp_address {
let entry_lp_addr: SocketAddr = if let Some(lp_addr) = &args.entry_lp_address {
lp_addr
.parse()
.map_err(|e| anyhow::anyhow!("Invalid entry-lp-address '{}': {}", lp_addr, e))?
} else if let Some(gw_ip) = &args.gateway_ip {
// Derive LP address from gateway IP
let ip: std::net::IpAddr = gw_ip
.parse()
.map_err(|e| anyhow::anyhow!("Invalid gateway-ip '{gw_ip}': {e}"))?;
.map_err(|e| anyhow::anyhow!("Invalid gateway-ip '{}': {}", gw_ip, e))?;
SocketAddr::new(ip, args.lp_port)
} else {
anyhow::bail!(
@@ -306,47 +246,20 @@ pub(crate) async fn run() -> anyhow::Result<ProbeResult> {
);
};
let entry_lp_node = TestedNodeLpDetails {
address: entry_lp_addr,
expected_kem_key_hashes,
expected_signing_key_hashes: todo!(),
x25519: x25519_key,
};
let entry_details = TestedNodeDetails::from_cli(identity, entry_lp_node);
let entry_details = TestedNodeDetails::from_cli(entry_identity, entry_lp_addr);
// Parse exit gateway if provided
let exit_details = if let Some(kem_key_digest) = &args.exit_gateway_kem_hey_hash_bs58 {
let exit_lp_addr = *args.exit_lp_address.as_ref().ok_or_else(|| {
anyhow::anyhow!("--exit-lp-address required with --exit-gateway-identity")
})?;
// SAFETY: if kem key digest is provided, all other LP data must also be present
// (enforced by clap)
let hash_fn: HashFunction = args
.exit_gateway_kem_key_hash_function
let exit_details = if let Some(exit_identity_str) = &args.exit_gateway_identity {
let exit_identity = NodeIdentity::from_base58_string(exit_identity_str)?;
let exit_lp_addr: SocketAddr = args
.exit_lp_address
.as_ref()
.unwrap()
.parse()?;
let kem_type: KEM = args.exit_gateway_kem_key_type.as_ref().unwrap().parse()?;
let x25519_key: x25519::PublicKey =
args.exit_gateway_x25519_key.as_ref().unwrap().parse()?;
let identity: ed25519::PublicKey =
args.exit_gateway_identity.as_ref().unwrap().parse()?;
let digest = bs58::decode(&kem_key_digest).into_vec()?;
let mut expected_kem_key_hashes = HashMap::new();
let mut digests = HashMap::new();
digests.insert(hash_fn, digest);
expected_kem_key_hashes.insert(kem_type, digests);
let exit_lp_node = TestedNodeLpDetails {
address: exit_lp_addr,
expected_kem_key_hashes,
expected_signing_key_hashes: Default::default(),
x25519: x25519_key,
};
Some(TestedNodeDetails::from_cli(identity, exit_lp_node))
.ok_or_else(|| {
anyhow::anyhow!("--exit-lp-address required with --exit-gateway-identity")
})?
.parse()
.map_err(|e| anyhow::anyhow!("Invalid exit-lp-address: {}", e))?;
Some(TestedNodeDetails::from_cli(exit_identity, exit_lp_addr))
} else {
None
};
+1 -1
View File
@@ -31,7 +31,7 @@ nym-exit-policy = { workspace = true }
nym-noise-keys = { workspace = true }
nym-wireguard-types = { workspace = true }
nym-upgrade-mode-check = { workspace = true, features = ["openapi"] }
nym-kkt-ciphersuite = { workspace = true }
nym-kkt-ciphersuite = { path = "../../common/nym-kkt-ciphersuite" }
# feature-specific dependencies:
@@ -22,28 +22,26 @@ pub struct LewesProtocol {
/// Digests of the KEM keys available to this node alongside hashing algorithms used
/// for their computation.
pub kem_keys: HashMap<LPKEM, HashMap<LPHashFunction, Vec<u8>>>,
/// Digests of the signing keys available to this node alongside hashing algorithms used
/// for their computation.
pub signing_keys: HashMap<LPSignatureScheme, HashMap<LPHashFunction, Vec<u8>>>,
}
impl LewesProtocol {
pub fn new(
enabled: bool,
control_port: u16,
data_port: u16,
kem_keys: HashMap<LPKEM, HashMap<LPHashFunction, Vec<u8>>>,
signing_keys: HashMap<LPSignatureScheme, HashMap<LPHashFunction, Vec<u8>>>,
) -> Self {
pub fn new(enabled: bool, control_port: u16, data_port: u16) -> Self {
LewesProtocol {
enabled,
control_port,
data_port,
kem_keys,
signing_keys,
kem_keys: Default::default(),
}
}
pub fn with_kem_key_hashes(
mut self,
kem: LPKEM,
hashes: HashMap<LPHashFunction, Vec<u8>>,
) -> Self {
self.kem_keys.insert(kem, hashes);
self
}
}
// explicitly redefine available HashFunctions and KEMs so that we would not
@@ -124,8 +122,8 @@ impl From<LPHashFunction> for nym_kkt_ciphersuite::HashFunction {
fn from(lp_hash_fnction: LPHashFunction) -> Self {
match lp_hash_fnction {
LPHashFunction::Blake3 => nym_kkt_ciphersuite::HashFunction::Blake3,
LPHashFunction::Shake128 => nym_kkt_ciphersuite::HashFunction::Shake128,
LPHashFunction::Shake256 => nym_kkt_ciphersuite::HashFunction::Shake256,
LPHashFunction::Shake128 => nym_kkt_ciphersuite::HashFunction::SHAKE128,
LPHashFunction::Shake256 => nym_kkt_ciphersuite::HashFunction::SHAKE256,
LPHashFunction::Sha256 => nym_kkt_ciphersuite::HashFunction::SHA256,
}
}
@@ -135,54 +133,16 @@ impl From<nym_kkt_ciphersuite::HashFunction> for LPHashFunction {
fn from(kem: nym_kkt_ciphersuite::HashFunction) -> Self {
match kem {
nym_kkt_ciphersuite::HashFunction::Blake3 => LPHashFunction::Blake3,
nym_kkt_ciphersuite::HashFunction::Shake128 => LPHashFunction::Shake128,
nym_kkt_ciphersuite::HashFunction::Shake256 => LPHashFunction::Shake256,
nym_kkt_ciphersuite::HashFunction::SHAKE128 => LPHashFunction::Shake128,
nym_kkt_ciphersuite::HashFunction::SHAKE256 => LPHashFunction::Shake256,
nym_kkt_ciphersuite::HashFunction::SHA256 => LPHashFunction::Sha256,
}
}
}
#[derive(
Serialize,
Deserialize,
Debug,
Clone,
Copy,
JsonSchema,
Hash,
PartialEq,
Eq,
PartialOrd,
Display,
EnumString,
EnumIter,
)]
#[strum(serialize_all = "lowercase")]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
pub enum LPSignatureScheme {
Ed25519,
}
impl From<LPSignatureScheme> for nym_kkt_ciphersuite::SignatureScheme {
fn from(lp_hash_fnction: LPSignatureScheme) -> Self {
match lp_hash_fnction {
LPSignatureScheme::Ed25519 => nym_kkt_ciphersuite::SignatureScheme::Ed25519,
}
}
}
impl From<nym_kkt_ciphersuite::SignatureScheme> for LPSignatureScheme {
fn from(kem: nym_kkt_ciphersuite::SignatureScheme) -> Self {
match kem {
nym_kkt_ciphersuite::SignatureScheme::Ed25519 => LPSignatureScheme::Ed25519,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use nym_kkt_ciphersuite::SignatureScheme;
#[test]
fn kem_display() {
@@ -199,9 +159,4 @@ mod tests {
assert_eq!(LPHashFunction::Shake256.to_string(), "shake256");
assert_eq!(LPHashFunction::Sha256.to_string(), "sha256");
}
#[test]
fn signature_scheme_display() {
assert_eq!(SignatureScheme::Ed25519.to_string(), "ed25519");
}
}
+7 -29
View File
@@ -51,9 +51,7 @@ use nym_network_requester::{
};
use nym_node_metrics::NymNodeMetrics;
use nym_node_metrics::events::MetricEventsSender;
use nym_node_requests::api::v1::lewes_protocol::models::{
LPHashFunction, LPKEM, LPSignatureScheme,
};
use nym_node_requests::api::v1::lewes_protocol::models::{LPHashFunction, LPKEM};
use nym_node_requests::api::v1::node::models::{AnnouncePorts, NodeDescription};
use nym_noise::config::{NoiseConfig, NoiseNetworkView};
use nym_noise_keys::VersionedNoiseKeyV1;
@@ -402,6 +400,7 @@ pub(crate) struct NymNode {
sphinx_key_manager: Option<SphinxKeyManager>,
// to be used when noise is integrated
#[allow(dead_code)]
x25519_noise_keys: Arc<x25519::KeyPair>,
}
@@ -645,7 +644,6 @@ impl NymNode {
let mut gateway_tasks_builder = GatewayTasksBuilder::new(
config.gateway,
self.ed25519_identity_keys.clone(),
self.x25519_noise_keys.clone(),
self.entry_gateway.psq_kem_key.clone(),
self.entry_gateway.client_storage.clone(),
mix_packet_sender,
@@ -776,7 +774,7 @@ impl NymNode {
Ok(())
}
fn compute_kem_key_hashes(&self) -> HashMap<LPKEM, HashMap<LPHashFunction, Vec<u8>>> {
fn compute_kem_key_hashes(&self) -> (LPKEM, HashMap<LPHashFunction, Vec<u8>>) {
let kem = LPKEM::X25519;
let kem_key_bytes = self.entry_gateway.psq_kem_key.public_key().as_bytes();
@@ -787,27 +785,7 @@ impl NymNode {
.map(|(f, d)| (f.into(), d))
.collect();
let mut hashes = HashMap::new();
hashes.insert(kem, digests);
hashes
}
fn compute_signing_key_hashes(
&self,
) -> HashMap<LPSignatureScheme, HashMap<LPHashFunction, Vec<u8>>> {
let scheme = LPSignatureScheme::Ed25519;
let kem_key_bytes = self.ed25519_identity_keys.public_key().as_bytes();
// convert from `nym_kkt_ciphersuite` types into `nym_nodes_requests`
let digests = produce_key_digests(kem_key_bytes.as_ref())
.into_iter()
.map(|(f, d)| (f.into(), d))
.collect();
let mut hashes = HashMap::new();
hashes.insert(scheme, digests);
hashes
(kem, digests)
}
pub(crate) async fn build_http_server(&self) -> Result<NymNodeHttpServer, NymNodeError> {
@@ -883,13 +861,13 @@ impl NymNode {
policy: None,
};
let (kem, hashes) = self.compute_kem_key_hashes();
let lp_details = api_requests::v1::lewes_protocol::models::LewesProtocol::new(
self.modes().entry,
self.config.gateway_tasks.lp.announced_control_port(),
self.config.gateway_tasks.lp.announced_data_port(),
self.compute_kem_key_hashes(),
self.compute_signing_key_hashes(),
);
)
.with_kem_key_hashes(kem, hashes);
let mut config = HttpServerConfig::new()
.with_landing_page_assets(self.config.http.landing_page_assets_path.as_ref())
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: GPL-3.0-only
use nym_credential_storage::persistent_storage::PersistentStorage;
use nym_registration_common::NymNodeInformation;
use nym_registration_common::NymNode;
use nym_sdk::{
DebugConfig, NymNetworkDetails, RememberMe, TopologyProvider, UserAgent,
mixnet::{
@@ -25,7 +25,7 @@ const MIXNET_CLIENT_STARTUP_TIMEOUT: Duration = Duration::from_secs(30);
#[derive(Clone)]
pub struct NymNodeWithKeys {
pub node: NymNodeInformation,
pub node: NymNode,
pub keys: Arc<x25519::KeyPair>,
}
+3
View File
@@ -93,6 +93,9 @@ pub enum RegistrationClientError {
#[source]
source: Box<crate::lp_client::LpClientError>,
},
#[error("failed to convert ed25519 pubkey into x25519 pubkey")]
X25519PubkeyConversionFailure,
}
impl RegistrationClientError {
+44 -41
View File
@@ -1,8 +1,9 @@
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use tokio_util::sync::CancellationToken;
use crate::config::RegistrationClientConfig;
use crate::lp_client::helpers::to_lp_remote_peer;
use nym_authenticator_client::{AuthClientMixnetListener, AuthenticatorClient};
use nym_bandwidth_controller::BandwidthTicketProvider;
use nym_credentials_interface::TicketType;
@@ -13,7 +14,12 @@ use nym_sdk::mixnet::{EventReceiver, MixnetClient, Recipient};
use rand::rngs::OsRng;
use std::sync::Arc;
use tokio::net::TcpStream;
use tokio_util::sync::CancellationToken;
mod builder;
mod config;
mod error;
mod lp_client;
mod types;
pub use builder::RegistrationClientBuilder;
pub use builder::config::{
@@ -23,17 +29,11 @@ pub use builder::config::{
pub use config::RegistrationMode;
pub use error::RegistrationClientError;
pub use lp_client::{LpConfig, LpRegistrationClient, NestedLpSession, error::LpClientError};
use nym_crypto::aes::cipher::crypto_common::rand_core::{CryptoRng, RngCore};
use nym_lp::peer::LpRemotePeer;
pub use types::{
LpRegistrationResult, MixnetRegistrationResult, RegistrationResult, WireguardRegistrationResult,
};
mod builder;
mod config;
mod error;
mod lp_client;
mod types;
pub struct RegistrationClient {
mixnet_client: MixnetClient,
config: RegistrationClientConfig,
@@ -154,14 +154,7 @@ impl RegistrationClient {
)))
}
// create dedicated method taking RNG instance for tests
async fn register_lp_with_rng<R>(
self,
rng: &mut R,
) -> Result<RegistrationResult, RegistrationClientError>
where
R: RngCore + CryptoRng,
{
async fn register_lp(self) -> Result<RegistrationResult, RegistrationClientError> {
// Extract and validate LP data
let entry_lp_data = self.config.entry.node.lp_data.ok_or(
RegistrationClientError::LpRegistrationNotPossible {
@@ -175,52 +168,69 @@ impl RegistrationClient {
},
)?;
let entry_address = entry_lp_data.address;
let exit_address = exit_lp_data.address;
tracing::debug!("Entry gateway LP address: {entry_address}");
tracing::debug!("Exit gateway LP address: {exit_address}");
tracing::debug!("Entry gateway LP address: {}", entry_lp_data.address);
tracing::debug!("Exit gateway LP address: {}", exit_lp_data.address);
// Generate fresh Ed25519 keypairs for LP registration
// These are ephemeral and used only for the LP handshake protocol
let entry_lp_keypair = Arc::new(ed25519::KeyPair::new(&mut OsRng));
let exit_lp_keypair = Arc::new(ed25519::KeyPair::new(&mut OsRng));
let entry_peer = to_lp_remote_peer(self.config.entry.node.identity, entry_lp_data);
let exit_peer = to_lp_remote_peer(self.config.exit.node.identity, exit_lp_data);
// Step 1: Derive X25519 keys from Ed25519 for the gateways
let entry_x25519_public = self
.config
.entry
.node
.identity
.to_x25519()
.map_err(|_| RegistrationClientError::X25519PubkeyConversionFailure)?;
// STEP 1: Establish outer session with entry gateway
let exit_x25519_public = self
.config
.exit
.node
.identity
.to_x25519()
.map_err(|_| RegistrationClientError::X25519PubkeyConversionFailure)?;
let entry_peer = LpRemotePeer::new(self.config.entry.node.identity, entry_x25519_public)
.with_kem_key_digests(entry_lp_data.expected_kem_key_hashes);
let exit_peer = LpRemotePeer::new(self.config.exit.node.identity, exit_x25519_public)
.with_kem_key_digests(exit_lp_data.expected_kem_key_hashes);
// STEP 2: Establish outer session with entry gateway
// This creates the LP session that will be used to forward packets to exit.
// Uses packet-per-connection model: each handshake packet on new TCP connection.
tracing::info!("Establishing outer session with entry gateway");
let mut entry_client = LpRegistrationClient::new_with_default_config(
entry_lp_keypair.clone(),
entry_peer,
entry_address,
entry_lp_data.address,
self.config.entry.node.ip_address,
);
// Perform handshake with entry gateway (outer session now established)
entry_client.perform_handshake().await.map_err(|source| {
RegistrationClientError::EntryGatewayRegisterLp {
gateway_id: self.config.entry.node.identity.to_base58_string(),
lp_address: entry_address,
lp_address: entry_lp_data.address,
source: Box::new(source),
}
})?;
tracing::info!("Outer session with entry gateway established");
// STEP 2: Use nested session to register with exit gateway via forwarding
// STEP 3: Use nested session to register with exit gateway via forwarding
// This hides the client's IP address from the exit gateway
tracing::info!("Registering with exit gateway via entry forwarding");
let mut nested_session =
NestedLpSession::new(exit_address.to_string(), exit_lp_keypair, exit_peer);
NestedLpSession::new(exit_lp_data.address.to_string(), exit_lp_keypair, exit_peer);
// Perform handshake and registration with exit gateway (all via entry forwarding)
let exit_gateway_data = nested_session
.handshake_and_register::<TcpStream, _>(
.handshake_and_register::<TcpStream>(
&mut entry_client,
rng,
&self.config.exit.keys,
&self.config.exit.node.identity,
&*self.bandwidth_controller,
@@ -229,17 +239,16 @@ impl RegistrationClient {
.await
.map_err(|source| RegistrationClientError::ExitGatewayRegisterLp {
gateway_id: self.config.exit.node.identity.to_base58_string(),
lp_address: exit_address,
lp_address: exit_lp_data.address,
source: Box::new(source),
})?;
tracing::info!("Exit gateway registration completed via forwarding");
// STEP 3: Register with entry gateway (packet-per-connection)
// STEP 4: Register with entry gateway (packet-per-connection)
tracing::info!("Registering with entry gateway");
let entry_gateway_data = entry_client
.register(
rng,
&self.config.entry.keys,
&self.config.entry.node.identity,
&*self.bandwidth_controller,
@@ -248,7 +257,7 @@ impl RegistrationClient {
.await
.map_err(|source| RegistrationClientError::EntryGatewayRegisterLp {
gateway_id: self.config.entry.node.identity.to_base58_string(),
lp_address: entry_address,
lp_address: entry_lp_data.address,
source: Box::new(source),
})?;
@@ -267,12 +276,6 @@ impl RegistrationClient {
})))
}
async fn register_lp(self) -> Result<RegistrationResult, RegistrationClientError> {
let mut rng = rand::thread_rng();
self.register_lp_with_rng(&mut rng).await
}
pub async fn register(self) -> Result<RegistrationResult, RegistrationClientError> {
self.cancel_token
.clone()
+27 -27
View File
@@ -19,10 +19,9 @@ use nym_lp::message::ForwardPacketData;
use nym_lp::peer::{LpLocalPeer, LpRemotePeer};
use nym_lp::state_machine::{LpAction, LpData, LpInput, LpStateMachine};
use nym_lp_transport::traits::LpTransport;
use nym_registration_common::{LpRegistrationRequest, WireguardConfiguration};
use nym_registration_common::{GatewayData, LpRegistrationRequest};
use nym_wireguard_types::PeerPublicKey;
use rand::{CryptoRng, RngCore};
use std::net::SocketAddr;
use std::net::{IpAddr, SocketAddr};
use std::sync::Arc;
use std::time::{SystemTime, UNIX_EPOCH};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
@@ -55,6 +54,9 @@ pub struct LpRegistrationClient<S = TcpStream> {
/// Created during handshake initiation. Persists across packet-per-connection calls.
state_machine: Option<LpStateMachine>,
/// Client's IP address for registration metadata.
client_ip: IpAddr,
/// Configuration for timeouts and TCP parameters.
config: LpConfig,
@@ -73,6 +75,7 @@ where
/// * `local_ed25519_keypair` - Client's Ed25519 identity keypair
/// * `gateway_lp_peer` - Encapsulates all the gateway keys needed for the Lewes Protocol
/// * `gateway_lp_address` - Gateway's LP listener socket address
/// * `client_ip` - Client IP address for registration
/// * `config` - Configuration for timeouts and TCP parameters (use `LpConfig::default()`)
///
/// # Note
@@ -81,6 +84,7 @@ where
local_ed25519_keypair: Arc<ed25519::KeyPair>,
gateway_lp_peer: LpRemotePeer,
gateway_lp_address: SocketAddr,
client_ip: IpAddr,
config: LpConfig,
) -> Self {
let local_x25519_keypair = local_ed25519_keypair.to_x25519();
@@ -90,6 +94,7 @@ where
gateway_lp_peer,
gateway_lp_address,
state_machine: None,
client_ip,
config,
stream: None,
}
@@ -110,11 +115,13 @@ where
local_ed25519_keypair: Arc<ed25519::KeyPair>,
gateway_lp_peer: LpRemotePeer,
gateway_lp_address: SocketAddr,
client_ip: IpAddr,
) -> Self {
Self::new(
local_ed25519_keypair,
gateway_lp_peer,
gateway_lp_address,
client_ip,
LpConfig::default(),
)
}
@@ -133,6 +140,11 @@ where
self.gateway_lp_address
}
/// Returns the client's IP address.
pub fn client_ip(&self) -> IpAddr {
self.client_ip
}
/// Returns reference to the established connection between the client and the gateway.
pub fn connection(&self) -> &Option<S> {
&self.stream
@@ -663,7 +675,6 @@ where
/// for that please use [`Self::register_with_retry`] instead
///
/// # Arguments
/// * `rng` - RNG instance for generating PSK
/// * `wg_keypair` - Client's WireGuard x25519 keypair
/// * `gateway_identity` - Gateway's ed25519 identity for credential verification
/// * `bandwidth_controller` - Provider for bandwidth credentials
@@ -680,17 +691,13 @@ where
/// - Network communication fails
/// - Gateway rejected the registration
/// - Response times out (see LpConfig::registration_timeout)
pub async fn register<R>(
pub async fn register(
&mut self,
rng: &mut R,
wg_keypair: &x25519::KeyPair,
gateway_identity: &ed25519::PublicKey,
bandwidth_controller: &dyn BandwidthTicketProvider,
ticket_type: TicketType,
) -> Result<WireguardConfiguration>
where
R: RngCore + CryptoRng,
{
) -> Result<GatewayData> {
tracing::debug!("Acquiring bandwidth credential for registration");
// Get bandwidth credential from controller
@@ -704,7 +711,7 @@ where
})?
.data;
self.register_with_credential(rng, wg_keypair, credential, ticket_type)
self.register_with_credential(wg_keypair, credential, ticket_type)
.await
}
@@ -714,7 +721,6 @@ where
/// Uses the persistent TCP connection established during handshake.
///
/// # Arguments
/// * `rng` - RNG instance for generating PSK
/// * `wg_keypair` - Client's WireGuard x25519 keypair
/// * `credential` - Pre-generated bandwidth credential
/// * `ticket_type` - Type of bandwidth ticket
@@ -728,21 +734,17 @@ where
///
/// # Panics / Errors
/// Returns error if handshake not completed or if connection was closed.
pub async fn register_with_credential<R>(
pub async fn register_with_credential(
&mut self,
rng: &mut R,
wg_keypair: &x25519::KeyPair,
credential: CredentialSpendingData,
ticket_type: TicketType,
) -> Result<WireguardConfiguration>
where
R: RngCore + CryptoRng,
{
) -> Result<GatewayData> {
tracing::debug!("Sending registration request (persistent connection)");
// 1. Build registration request
let wg_public_key = PeerPublicKey::new(wg_keypair.public_key().to_bytes().into());
let request = LpRegistrationRequest::new_dvpn(rng, wg_public_key, credential, ticket_type);
let request = LpRegistrationRequest::new_dvpn(wg_public_key, credential, ticket_type);
tracing::trace!("Built registration request: {:?}", request);
@@ -861,7 +863,6 @@ where
/// will return the cached result instead of spending a new credential.
///
/// # Arguments
/// * `rng` - RNG instance for generating PSK
/// * `wg_keypair` - Client's WireGuard x25519 keypair (same key used for all retries)
/// * `gateway_identity` - Gateway's ed25519 identity for credential verification
/// * `bandwidth_controller` - Provider for bandwidth credentials
@@ -877,18 +878,14 @@ where
/// # Note
/// Unlike `register()`, this method handles the full flow including handshake.
/// Do NOT call `perform_handshake()` before this method.
pub async fn register_with_retry<R>(
pub async fn register_with_retry(
&mut self,
rng: &mut R,
wg_keypair: &x25519::KeyPair,
gateway_identity: &ed25519::PublicKey,
bandwidth_controller: &dyn BandwidthTicketProvider,
ticket_type: TicketType,
max_retries: u32,
) -> Result<WireguardConfiguration>
where
R: RngCore + CryptoRng,
{
) -> Result<GatewayData> {
tracing::debug!("Starting resilient registration (max_retries={max_retries})",);
// Acquire credential ONCE before any attempts
@@ -932,7 +929,7 @@ where
}
match self
.register_with_credential(rng, wg_keypair, credential.clone(), ticket_type)
.register_with_credential(wg_keypair, credential.clone(), ticket_type)
.await
{
Ok(data) => {
@@ -1182,14 +1179,17 @@ mod tests {
let gateway_peer =
LpRemotePeer::new(*gateway_ed_keys.public_key(), *gateway_x_keys.public_key());
let address = "127.0.0.1:41264".parse().unwrap();
let client_ip = "192.168.1.100".parse().unwrap();
let client = LpRegistrationClient::<TcpStream>::new_with_default_config(
keypair,
gateway_peer,
address,
client_ip,
);
assert!(!client.is_handshake_complete());
assert_eq!(client.gateway_address(), address);
assert_eq!(client.client_ip(), client_ip);
}
}
@@ -2,13 +2,9 @@
// SPDX-License-Identifier: Apache-2.0
use crate::LpClientError;
use nym_crypto::asymmetric::ed25519;
use nym_lp::message::ForwardPacketData;
use nym_lp::peer::LpRemotePeer;
use nym_lp::state_machine::{LpAction, LpData, LpDataKind, LpInput};
use nym_registration_common::{
LpRegistrationRequest, LpRegistrationResponse, NymNodeLPInformation,
};
use nym_registration_common::{LpRegistrationRequest, LpRegistrationResponse};
pub(crate) fn convert_registration_request(
request: LpRegistrationRequest,
@@ -85,13 +81,3 @@ pub(crate) fn try_convert_forward_response(action: LpAction) -> Result<Vec<u8>,
Ok(response_data.content.into())
}
pub(crate) fn to_lp_remote_peer(
identity: ed25519::PublicKey,
data: NymNodeLPInformation,
) -> LpRemotePeer {
LpRemotePeer::new(identity, data.x25519).with_key_digests(
data.expected_kem_key_hashes,
data.expected_signing_key_hashes,
)
}
@@ -30,9 +30,8 @@ use nym_lp::peer::{LpLocalPeer, LpRemotePeer};
use nym_lp::state_machine::{LpAction, LpInput, LpStateMachine};
use nym_lp::{LpMessage, LpPacket};
use nym_lp_transport::traits::LpTransport;
use nym_registration_common::{LpRegistrationRequest, WireguardConfiguration};
use nym_registration_common::{GatewayData, LpRegistrationRequest};
use nym_wireguard_types::PeerPublicKey;
use rand::{CryptoRng, RngCore};
use std::sync::Arc;
use std::time::{SystemTime, UNIX_EPOCH};
@@ -288,17 +287,15 @@ impl NestedLpSession {
///
/// # Returns
/// * `Ok(GatewayData)` - Exit gateway configuration data on successful registration
pub async fn handshake_and_register_with_credential<S, R>(
pub async fn handshake_and_register_with_credential<S>(
&mut self,
outer_client: &mut LpRegistrationClient<S>,
rng: &mut R,
wg_keypair: &x25519::KeyPair,
credential: nym_credentials_interface::CredentialSpendingData,
ticket_type: TicketType,
) -> Result<WireguardConfiguration>
) -> Result<GatewayData>
where
S: LpTransport + Unpin,
R: RngCore + CryptoRng,
{
// Step 1: Perform handshake with exit gateway via forwarding
self.perform_handshake(outer_client).await?;
@@ -314,7 +311,7 @@ impl NestedLpSession {
// Step 3: Build registration request (credential already provided)
let wg_public_key = PeerPublicKey::new(wg_keypair.public_key().to_bytes().into());
let request = LpRegistrationRequest::new_dvpn(rng, wg_public_key, credential, ticket_type);
let request = LpRegistrationRequest::new_dvpn(wg_public_key, credential, ticket_type);
tracing::trace!("Built registration request: {:?}", request);
@@ -428,18 +425,16 @@ impl NestedLpSession {
/// - Forwarding through entry gateway fails
/// - Response decryption/deserialization fails
/// - Gateway rejects the registration
pub async fn handshake_and_register<S, R>(
pub async fn handshake_and_register<S>(
&mut self,
outer_client: &mut LpRegistrationClient<S>,
rng: &mut R,
wg_keypair: &x25519::KeyPair,
gateway_identity: &ed25519::PublicKey,
bandwidth_controller: &dyn BandwidthTicketProvider,
ticket_type: TicketType,
) -> Result<WireguardConfiguration>
) -> Result<GatewayData>
where
S: LpTransport + Unpin,
R: RngCore + CryptoRng,
{
// Step 1: Perform handshake with exit gateway via forwarding
self.perform_handshake(outer_client).await?;
@@ -466,7 +461,7 @@ impl NestedLpSession {
// Step 4: Build registration request
let wg_public_key = PeerPublicKey::new(wg_keypair.public_key().to_bytes().into());
let request = LpRegistrationRequest::new_dvpn(rng, wg_public_key, credential, ticket_type);
let request = LpRegistrationRequest::new_dvpn(wg_public_key, credential, ticket_type);
tracing::trace!("Built registration request: {:?}", request);
@@ -582,19 +577,17 @@ impl NestedLpSession {
/// # Errors
/// Returns an error if all retry attempts fail.
#[allow(clippy::too_many_arguments)]
pub async fn handshake_and_register_with_retry<S, R>(
pub async fn handshake_and_register_with_retry<S>(
&mut self,
rng: &mut R,
outer_client: &mut LpRegistrationClient<S>,
wg_keypair: &x25519::KeyPair,
gateway_identity: &ed25519::PublicKey,
bandwidth_controller: &dyn BandwidthTicketProvider,
ticket_type: TicketType,
max_retries: u32,
) -> Result<WireguardConfiguration>
) -> Result<GatewayData>
where
S: LpTransport + Unpin,
R: RngCore + CryptoRng,
{
tracing::debug!(
"Starting resilient exit registration (max_retries={})",
@@ -642,7 +635,6 @@ impl NestedLpSession {
match self
.handshake_and_register_with_credential(
outer_client,
rng,
wg_keypair,
credential.clone(),
ticket_type,
+5 -5
View File
@@ -3,7 +3,7 @@
use nym_authenticator_client::{AuthClientMixnetListenerHandle, AuthenticatorClient};
use nym_bandwidth_controller::BandwidthTicketProvider;
use nym_registration_common::{AssignedAddresses, WireguardConfiguration};
use nym_registration_common::{AssignedAddresses, GatewayData};
use nym_sdk::mixnet::{EventReceiver, MixnetClient};
pub enum RegistrationResult {
@@ -21,8 +21,8 @@ pub struct MixnetRegistrationResult {
pub struct WireguardRegistrationResult {
pub entry_gateway_client: AuthenticatorClient,
pub exit_gateway_client: AuthenticatorClient,
pub entry_gateway_data: WireguardConfiguration,
pub exit_gateway_data: WireguardConfiguration,
pub entry_gateway_data: GatewayData,
pub exit_gateway_data: GatewayData,
pub authenticator_listener_handle: AuthClientMixnetListenerHandle,
pub bw_controller: Box<dyn BandwidthTicketProvider>,
}
@@ -39,10 +39,10 @@ pub struct WireguardRegistrationResult {
/// * `bw_controller` - Bandwidth ticket provider for credential management
pub struct LpRegistrationResult {
/// Gateway configuration data from entry gateway
pub entry_gateway_data: WireguardConfiguration,
pub entry_gateway_data: GatewayData,
/// Gateway configuration data from exit gateway
pub exit_gateway_data: WireguardConfiguration,
pub exit_gateway_data: GatewayData,
/// Bandwidth controller for credential management
pub bw_controller: Box<dyn BandwidthTicketProvider>,
-1
View File
@@ -4229,7 +4229,6 @@ dependencies = [
"nym-crypto",
"nym-ecash-signer-check-types",
"nym-ecash-time",
"nym-kkt-ciphersuite",
"nym-mixnet-contract-common",
"nym-network-defaults",
"nym-node-requests",
+1 -1
View File
@@ -28,7 +28,7 @@ url = { workspace = true }
# Nym crates
nym-api-requests = { path = "../../nym-api/nym-api-requests" }
nym-crypto = { path = "../../common/crypto" }
nym-kkt-ciphersuite = { workspace = true }
nym-kkt-ciphersuite = { path = "../../common/nym-kkt-ciphersuite" }
nym-http-api-client = { path = "../../common/http-api-client" }
nym-kcp = { path = "../../common/nym-kcp" }
nym-lp = { path = "../../common/nym-lp" }
+8 -8
View File
@@ -117,16 +117,16 @@ impl SpeedtestClient {
self.gateway.lp_address
);
let client_ip = "0.0.0.0".parse()?;
let gw_peer = LpRemotePeer::new(self.gateway.identity, self.gateway.identity.to_x25519()?)
.with_key_digests(
self.gateway.kem_key_hashes.clone(),
self.gateway.signing_key_hashes.clone(),
);
.with_kem_key_digests(self.gateway.kem_key_hashes.clone());
let mut lp_client = LpRegistrationClient::<TcpStream>::new_with_default_config(
self.identity_keypair.clone(),
gw_peer,
self.gateway.lp_address,
client_ip,
);
let start = Instant::now();
@@ -163,16 +163,16 @@ impl SpeedtestClient {
self.gateway.lp_address
);
let client_ip = "0.0.0.0".parse()?;
let gw_peer = LpRemotePeer::new(self.gateway.identity, self.gateway.identity.to_x25519()?)
.with_key_digests(
self.gateway.kem_key_hashes.clone(),
self.gateway.signing_key_hashes.clone(),
);
.with_kem_key_digests(self.gateway.kem_key_hashes.clone());
let mut lp_client = LpRegistrationClient::new_with_default_config(
self.identity_keypair.clone(),
gw_peer,
self.gateway.lp_address,
client_ip,
);
let start = Instant::now();
+1 -2
View File
@@ -10,7 +10,7 @@ use nym_api_requests::models::{LPHashFunction, LPKEM};
use nym_api_requests::nym_nodes::SkimmedNode;
use nym_crypto::asymmetric::ed25519;
use nym_http_api_client::UserAgent;
use nym_kkt_ciphersuite::{KEMKeyDigests, SignatureScheme, SigningKeyDigests, KEM};
use nym_kkt_ciphersuite::{KEMKeyDigests, KEM};
use nym_sphinx_types::Node as SphinxNode;
use nym_topology::{NymRouteProvider, NymTopology, NymTopologyMetadata};
use nym_validator_client::nym_api::NymApiClientExt;
@@ -31,7 +31,6 @@ const LP_DATA_PORT: u16 = 51264;
pub struct GatewayInfo {
pub identity: ed25519::PublicKey,
pub kem_key_hashes: HashMap<KEM, KEMKeyDigests>,
pub signing_key_hashes: HashMap<SignatureScheme, SigningKeyDigests>,
pub sphinx_key: nym_crypto::asymmetric::x25519::PublicKey,
/// Mix host (IP:port for Sphinx mixing)