Commit Graph

5 Commits

Author SHA1 Message Date
Drazen Urch ecdeeb096e KKT + PSQ (#6203)
* Add nymkkt with KKT convenience wrappers for nym-lp integration

Integrates nymkkt module from georgio/noise-psq branch to enable
post-quantum key distribution for nym-lp.

Changes:
- Add common/nymkkt from georgio/noise-psq (KKT protocol implementation)
- Add convenience wrapper layer (kkt.rs) with simplified API:
  - request_kem_key() - Client requests gateway's KEM key
  - validate_kem_response() - Client validates signed response
  - handle_kem_request() - Gateway handles requests
- Add nymkkt to workspace members in root Cargo.toml
- Export kkt module in lib.rs

The KKT (Key Encapsulation Mechanism Transport) protocol enables efficient
distribution of post-quantum KEM public keys. Instead of storing large PQ
keys in the directory (1KB-500KB), we store 32-byte hashes and fetch actual
keys on-demand via this authenticated protocol.

Tests: All 5 unit tests passing (authenticated, anonymous, signature
verification, hash validation)

* feat(lp): add Ed25519 authentication to PSQ protocol

Replace basic PSQ v0 API with authenticated v1 API that includes
cryptographic authentication via Ed25519 signatures.

Changes:
- PSQ initiator now signs encapsulated keys with Ed25519 private key
- PSQ responder verifies Ed25519 signatures before deriving PSK
- Prevents MITM attacks through mutual authentication
- Fixed test helpers to use role-based Ed25519 keypair assignment
  (initiator uses [1u8;32], responder uses [2u8;32])

Security: This adds a critical authentication layer to the post-quantum
PSK derivation protocol, ensuring both parties can verify each other's
identity during the handshake.

Tests: All 77 tests passing (was 11 failures, now 0)

* feat(lp): integrate PSQ post-quantum PSK derivation

Complete integration of Post-Quantum Secure (PSQ) protocol for PSK
derivation in the Lewes Protocol, replacing simple Blake3 derivation
with cryptographically secure DHKEM-based PSK establishment.

This commit encompasses three completed tasks:

- Add KKTRequest/KKTResponse message types to LpMessage enum
- Update codec to handle KKT message serialization/deserialization
- Add kkt_orchestrator.rs with high-level KKT API wrappers
- Enable key exchange orchestration for PSQ protocol

- Add set_psk() method to NoiseProtocol for dynamic PSK injection
- Integrate PSQ derivation into LpSession handshake flow
- PSQ payload embedded in first Noise message (ClientHello)
- Derive PSK using libcrux-psq before Noise handshake completion
- Add helper functions for X25519 to KEM conversions

- Add comprehensive PSQ integration tests in session_integration/
- Test PSQ handshake end-to-end flow
- Validate PSK derivation correctness between initiator/responder
- Test PSQ + Noise combined protocol operation

Dependencies:
- libcrux-psq: Post-quantum PSK protocol implementation
- libcrux-kem: Key Encapsulation Mechanism primitives
- nym-kkt: KKT key exchange protocol wrappers
- rand 0.9: Required for KKT compatibility

Security: This adds Harvest-Now-Decrypt-Later (HNDL) resistance by
combining classical ECDH with post-quantum KEM for PSK derivation.
Even if X25519 is broken by quantum computers, the PSK remains secure.

Tests: All 77 tests passing

* feat(lp): add PSQ error handling documentation and tests (nym-bbi)

Formalize the "always abort" error handling strategy for PSQ failures.
PSQ errors indicate attacks, misconfigurations, or protocol violations
that should not be silently ignored or worked around.

Changes:
- Add comprehensive error handling documentation to psk.rs module
- Add diagnostic logging with error categorization:
  * CredError → warn about potential attack
  * TimestampElapsed → warn about potential replay
  * Other errors → log as errors
- Add 4 error scenario tests:
  * test_psq_deserialization_failure
  * test_handshake_abort_on_psq_failure
  * test_psq_invalid_signature
  * test_psq_state_unchanged_on_error
- Add log dependency to Cargo.toml

Error handling strategy: All PSQ failures abort the handshake cleanly
with no retry or fallback. This prevents silent security degradation
and ensures misconfigurations are detected early.

State guarantees: PSQ errors leave session in clean state - dummy PSK
remains, Noise HandshakeState unchanged, no partial data, no cleanup needed.

Tests: 81 tests passing (77 original + 4 new error tests)

Closes: nym-bbi

* feat(lp): add PSK injection tracking to prevent dummy PSK usage (nym-ep2)

Add safety mechanism to ensure real post-quantum PSK was injected before
allowing transport mode operations (encrypt/decrypt). This prevents
accidentally using the insecure dummy PSK [0u8; 32] if PSQ injection fails.

Changes:
- Add `psk_injected: AtomicBool` field to LpSession
- Initialize to `false` in LpSession::new()
- Set to `true` after successful PSK injection:
  * Initiator: In prepare_handshake_message() after set_psk()
  * Responder: In process_handshake_message() after set_psk()
- Add NoiseError::PskNotInjected error variant
- Add PSK injection checks in encrypt_data() and decrypt_data()
  * Check happens before handshake completion check
  * Returns PskNotInjected if flag is false
- Add comprehensive PSK injection lifecycle documentation to LpSession
- Add test_transport_fails_without_psk_injection test
- Update test_encrypt_decrypt_before_handshake to expect PskNotInjected

PSK Injection Lifecycle:
1. Session created with dummy PSK [0u8; 32] in Noise HandshakeState
2. During handshake, PSQ runs and derives real post-quantum PSK
3. Real PSK injected via set_psk() - psk_injected flag set to true
4. Handshake completes, transport mode available
5. Transport operations check psk_injected flag for safety

This is defensive programming - normal PSQ flow always injects the real PSK.
The safety check prevents transport mode if PSQ somehow fails silently or is
bypassed due to implementation bugs.

Tests: 82 tests passing (81 original + 1 new)

Closes: nym-ep2

* docs(lp): fix PSK state documentation inaccuracy

Correct error handling documentation to clarify that PSK slot 3
remains unmodified only on error, not in all cases.

Previous: "PSK slot 3 = dummy [0u8; 32] (never modified)"
Corrected: "PSK slot 3 = dummy [0u8; 32] (not modified on error)"

This is more accurate since:
- On error: PSK remains as dummy value (never injected)
- On success: PSK is replaced with real post-quantum PSK

Documentation-only change, no functional impact.

* feat(lp): add KKTExchange state to state machine for pre-handshake KEM key transfer (nym-4za)

Add KKTExchange state to LpStateMachine to properly orchestrate KKT (KEM Key Transfer)
protocol before Noise handshake begins. This enables dynamic KEM public key exchange,
allowing post-quantum KEM algorithms to be used without pre-published keys.

Changes:
- Add KKTExchange state and KKTComplete action to state machine
- Implement automatic KKT exchange on StartHandshake:
  * Initiator: sends KKT request → waits for response → validates signature
  * Responder: waits for request → validates → sends signed KEM key
- Update process_kkt_response() to accept Option<&[u8]> for hash validation:
  * Some(hash): full KKT validation with directory hash (future)
  * None: signature-only mode (current deployment)
- Add local_x25519_public() helper for responder KEM key derivation
- Update state flow: ReadyToHandshake → KKTExchange → Handshaking → Transport
- Add PSK handle storage (psk_handle) for future re-registration
- Export generate_fresh_salt() for session creation
- Update psq_responder_process_message() to return encrypted PSK handle (ctxt_B)
- Add comprehensive tests:
  * test_kkt_exchange_initiator_flow
  * test_kkt_exchange_responder_flow
  * test_kkt_exchange_full_roundtrip
  * test_kkt_exchange_close
  * test_kkt_exchange_rejects_invalid_inputs
  * Updated test_state_machine_simplified_flow for KKT phase

All tests passing. Ready for nym-8y5 (PSQ handshake KKT integration).

* docs(lp): add state machine and post-quantum security protocol documentation

Add comprehensive documentation of the Lewes Protocol state machine and
post-quantum security architecture to LP_PROTOCOL.md.

New sections:
- State Machine and Security Protocol overview
- Detailed state transition diagram (ReadyToHandshake → KKTExchange → Handshaking → Transport)
- Complete message sequence diagram showing KKT + PSQ + Noise flow
- KKT (KEM Key Transfer) protocol specification
- PSQ (Post-Quantum Secure PSK) protocol details
- Security guarantees and implementation status
- Algorithm choices (current X25519, future ML-KEM-768)
- Message type specifications for KKT
- Version 1.1 changelog entry documenting KKT/PSQ integration

Documentation includes:
- ASCII art state machine diagram
- Message sequence diagram with all protocol phases
- PSK derivation formulas
- Security properties checklist
- Migration path to post-quantum KEMs
- Integration details (PSQ embedded in Noise, no extra round-trips)

Related to nym-4za (KKTExchange state implementation).

* feat(lp): use KKT-authenticated KEM key in PSQ handshake (nym-8y5)

Replace direct X25519→KEM conversion with KKT-derived authenticated key
in PSQ initiator flow. This ensures PSQ uses the responder's authenticated
KEM public key obtained via KKT protocol instead of blindly converting
their X25519 key, properly completing the post-quantum security chain.

Changes:
- session.rs: Extract KEM key from KKTState::Completed in prepare_handshake_message()
- session.rs: Add set_kkt_completed_for_test() helper for test initialization
- session.rs: Update create_handshake_test_session() to initialize KKT state
- session.rs: Fix test_handshake_abort_on_psq_failure and test_psq_invalid_signature
- session_manager.rs: Add init_kkt_for_test() for integration test setup
- session_integration/mod.rs: Update tests for KKT-first flow (6 rounds total)
- session_integration/mod.rs: Fix state machine test expectations for KKTExchange state

All 87 tests passing. Unblocks nym-w8f (KKT tests) and nym-m15 (production integration).

* feat(lp): simplify API to Ed25519-only, derive X25519 internally

Refactored LP state machine to use Ed25519 keys exclusively in the public
API, with X25519 keys derived internally via RFC 7748. This simplifies the
API from 6 parameters to 4 while maintaining protocol security.

**Core API Changes:**
- LpStateMachine::new(): Removed explicit X25519 keypair parameters
- Old: new(is_initiator, local_keypair, local_ed25519_keypair,
         remote_public_key, remote_ed25519_key, salt)
- New: new(is_initiator, local_ed25519_keypair, remote_ed25519_key, salt)
- X25519 keys now derived internally from Ed25519 using RFC 7748
- lp_id calculation moved inside state machine (uses derived X25519 keys)

**Protocol Changes:**
- ClientHello message extended from 65 to 97 bytes
- Now includes client_ed25519_public_key field (32 bytes)
- Required for PSQ authentication in KKT + PSQ handshake flow
- Breaking change: gateway must extract Ed25519 from ClientHello

**Gateway Updates:**
- receive_client_hello() now extracts Ed25519 public key
- LpGatewayHandshake::new_responder() accepts Ed25519 keys only
- Removed manual X25519 conversion (handled by state machine)

**Registration Client Updates:**
- LpRegistrationClient now uses Ed25519 keypairs
- Generate fresh ephemeral Ed25519 keys for LP registration
- ClientHello includes Ed25519 public key for gateway authentication
- Fixed 7 pre-existing build errors:
  * mixnet_client_startup_timeout field removal
  * IprClientConnect API change (async → sync)
  * Error variant renames (use helper function)
  * LP client key type mismatches (X25519 → Ed25519)

**Test Suite:**
- Updated 16+ test functions to use new 4-parameter constructor
- Fixed 5 integration test failures caused by lp_id mismatch
- Tests now derive X25519 from Ed25519 (matching production behavior)
- Added missing PublicKey imports in test modules
- All 87 tests passing (100% success rate)

**Implementation Details:**
- Added Ed25519RecoveryError variant to LpError enum
- Type conversion: nym_crypto X25519 → nym_lp keypair types
- Maintained backward compatibility for PSQ/KKT protocol flow
- Session manager updated to use new API signature

This change completes the Ed25519-only API migration, hiding X25519 as an
implementation detail while preserving all security properties of the
KKT-authenticated PSQ handshake protocol.

* chore: run cargo fmt

* chore: run cargo clippy --fix to resolve simple linter issues

* Basic handshake working

* Final tweaks

* Wrap PR comments, 2024

---------

Co-authored-by: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
2025-11-21 18:37:38 +01:00
Jędrzej Stuczyński d73b7b7127 chore: remove support for legacy mixnode within the performance contract (#6205) 2025-11-14 15:04:59 +00:00
Drazen Urch 90e9e3cff8 Domain fronting integration (#5974)
* feat: unify HTTP client creation and enable domain fronting

Enhanced the base nym_http_api_client to reduce fragmentation and enable domain fronting:

- Added SerializationFormat enum for explicit JSON/bincode choice (no auto-detection)
- Added from_network() method to create clients from NymNetworkDetails with domain fronting
- Added with_bincode() builder method for explicit serialization configuration
- Set Accept header based on serialization preference
- Added deprecation paths for NymApiClient wrapper and nym_api::Client re-export
- Enabled domain fronting support via network defaults feature

This is part of a broader effort to consolidate HTTP client implementations across the codebase,
reducing ~500 lines of wrapper code and providing automatic domain fronting for censorship resistance.

* feat: migrate NymApiClient usage to unified HTTP client

- Wire up domain fronting configuration in NymNetworkDetails
- Implement NymApiClientExt trait for base nym_http_api_client::Client
- Migrate direct NymApiClient usage in multiple components:
  - nym-network-monitor
  - verloc measurements
  - connection tester
  - coconut/ecash client
  - validator rewarder
- Add Copy derive to ApiUrlConst to enable iteration
- Update error handling and Display implementations

This enables automatic domain fronting for all Nym API calls via the configured CDN front hosts.

* fix: resolve all compilation errors after NymApiClient migration

- Add missing nym-http-api-client dependencies to multiple crates
- Add NymApiClientExt trait imports where needed
- Fix type mismatches from NymApiClient to unified Client
- Add error conversions for NymAPIError in various error enums
- Implement missing trait methods (get_current_rewarded_set, get_all_basic_nodes_with_metadata, get_all_described_nodes)
- Fix type conversions for RewardedSetResponse in network monitor
- Update all API client instantiation to use new unified HTTP client

* feat: complete migration to unified HTTP client and fix all compilation errors

- Added missing NymApiClientExt trait methods (get_all_expanded_nodes, change_base_urls)
- Fixed all compilation errors across the workspace
- Updated nym-node to use unified client instead of deprecated NymApiClient
- Fixed type conversions for RewardedSetResponse → EpochRewardedSet
- Added nym-http-api-client dependency where needed
- Updated all examples and documentation to use new client API

* fix: provide all API URLs for automatic failover in endpoint rotation

Previously, when rotating API endpoints, only a single URL was provided to the
HTTP client, defeating the purpose of having multiple URLs for resilience.

Changes:
- NymApiTopologyProvider now provides all URLs in rotated order when switching endpoints
- NymApisClient similarly provides all URLs starting from the working endpoint
- Added clarifying comments for broadcast/exhaustive query methods where single URLs are intentionally used
- This enables the HTTP client's built-in failover mechanism while maintaining endpoint rotation behavior

The fix ensures that if the primary endpoint fails, the client can automatically
failover to alternative endpoints without manual intervention, improving overall
network resilience.

* Update common/client-core/src/client/base_client/mod.rs

Co-authored-by: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>

* Remove error generics, address PR comments

* Explicit warning on missing fronting configuration

* Assorted CI fixes

* Registry proc-macro

* Rename macro

* Syn workspace version

* Where do we need to put inventory

* Ergonomics and call sites, incept the builder

* fix: Address critical issues in client configuration registry implementation

- Fixed HeaderMapInit parsing bug that would cause compilation errors
- Added comprehensive documentation with usage examples and DSL reference
- Improved error handling with better error messages for invalid headers
- Added test coverage for both macro and registry functionality
- Added debug inspection capabilities for registered configurations
- Fixed module name conflicts in tests by using separate modules

All tests now passing:
- 7 macro tests validating DSL parsing and code generation
- 4 registry tests verifying configuration collection and application

* Use default value for the ports until api is deployed

* Feature/improved http error (#6025)

* use display impl for urls

* feat: attempt to add more details to reqwest errors

* temporarily restored GenericRequestFailure variant

* another restoration

* cleanup

* Some debug tooling, and default timeout fix

* Fix user-agent override

* Fix various wasm things

---------

Co-authored-by: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
Co-authored-by: Bogdan-Ștefan Neacşu <bogdan@nymtech.net>
2025-09-15 14:32:15 +02:00
Jędrzej Stuczyński d0692a567a feat: basic performance contract integration [within Nym API] (#5871)
* renamed nym-api config fields

* decouple rewarder startup from network monitor

* additional sections in nym-api config

* removed vesting queries in circulating supply calculator

* added memoized field for last submitted performance measurement

* wip: performance contract refresher

* cleaned up various contract caches

* modified cache refresher to allow passing update fn

* implement performance cache refreshing

* updated lefthook.yml to run cargo fmt

* impl NodePerformanceProvider trait

* dynamically using specific performance provider

* pre warm up performance contract cache and forbid the mode if its empty

* clippy

* introduce fallback setting for performance contract if value for given epoch is not available

* move some functions around
2025-07-01 11:29:50 +01:00
Jędrzej Stuczyński 6de0c4ce92 feat: initial performance contract (#5833)
* initialised basic structure for the performance contract

* shared code for contract testing

* unified common testing methods between performance and nym pool contracts

* impl of ExecuteMsg for the contract

* impl of QueryMsg for the contract

* setting initial authorised NMs during instantiation

* additional tests and fixes

* ibid

* scaffolding for client traits

* completed client traits

* clippy

* naive add performance contract to testnet manager

* placeholder values for the performance contract address

* introduced admin messages to purge old measurements from the storage

* introduced check ensuring performance data is only added to bonded nodes
2025-06-20 09:06:56 +01:00