[Feature] Noise XKpsk3 integration (2025 version) (#5692)
* grand Noise squaheroo * fix merge conflicts and adapt code for the key rotation changes (#5824) * remove file that should have been ignored
This commit is contained in:
@@ -55,7 +55,7 @@ pub(crate) async fn host_information(
|
||||
rotation_id: primary_key.rotation_id(),
|
||||
public_key: primary_pubkey,
|
||||
},
|
||||
x25519_noise: state.static_information.x25519_noise_key,
|
||||
x25519_versioned_noise: state.static_information.x25519_versioned_noise_key,
|
||||
pre_announced_x25519_sphinx_key: pre_announced,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
use crate::node::http::state::load::CachedNodeLoad;
|
||||
use crate::node::http::state::metrics::MetricsAppState;
|
||||
use crate::node::key_rotation::active_keys::ActiveSphinxKeys;
|
||||
use nym_crypto::asymmetric::{ed25519, x25519};
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
use nym_node_metrics::NymNodeMetrics;
|
||||
use nym_noise_keys::VersionedNoiseKey;
|
||||
use nym_verloc::measurements::SharedVerlocStats;
|
||||
use std::net::IpAddr;
|
||||
use std::sync::Arc;
|
||||
@@ -17,7 +18,7 @@ pub mod metrics;
|
||||
|
||||
pub(crate) struct StaticNodeInformation {
|
||||
pub(crate) ed25519_identity_keys: Arc<ed25519::KeyPair>,
|
||||
pub(crate) x25519_noise_key: Option<x25519::PublicKey>,
|
||||
pub(crate) x25519_versioned_noise_key: Option<VersionedNoiseKey>,
|
||||
pub(crate) ip_addresses: Vec<IpAddr>,
|
||||
pub(crate) hostname: Option<String>,
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
use crate::node::mixnet::shared::SharedData;
|
||||
use futures::StreamExt;
|
||||
use nym_noise::connection::Connection;
|
||||
use nym_noise::upgrade_noise_responder;
|
||||
use nym_sphinx_forwarding::packet::MixPacket;
|
||||
use nym_sphinx_framing::codec::NymCodec;
|
||||
use nym_sphinx_framing::packet::FramedNymPacket;
|
||||
@@ -72,7 +74,6 @@ impl PendingReplayCheckPackets {
|
||||
|
||||
pub(crate) struct ConnectionHandler {
|
||||
shared: SharedData,
|
||||
mixnet_connection: Framed<TcpStream, NymCodec>,
|
||||
remote_address: SocketAddr,
|
||||
|
||||
// packets pending for replay detection
|
||||
@@ -89,11 +90,7 @@ impl Drop for ConnectionHandler {
|
||||
}
|
||||
|
||||
impl ConnectionHandler {
|
||||
pub(crate) fn new(
|
||||
shared: &SharedData,
|
||||
tcp_stream: TcpStream,
|
||||
remote_address: SocketAddr,
|
||||
) -> Self {
|
||||
pub(crate) fn new(shared: &SharedData, remote_address: SocketAddr) -> Self {
|
||||
let shutdown = shared.shutdown.child_token(remote_address.to_string());
|
||||
shared.metrics.network.new_active_ingress_mixnet_client();
|
||||
|
||||
@@ -104,11 +101,11 @@ impl ConnectionHandler {
|
||||
replay_protection_filter: shared.replay_protection_filter.clone(),
|
||||
mixnet_forwarder: shared.mixnet_forwarder.clone(),
|
||||
final_hop: shared.final_hop.clone(),
|
||||
noise_config: shared.noise_config.clone(),
|
||||
metrics: shared.metrics.clone(),
|
||||
shutdown,
|
||||
},
|
||||
remote_address,
|
||||
mixnet_connection: Framed::new(tcp_stream, NymCodec),
|
||||
pending_packets: PendingReplayCheckPackets::new(),
|
||||
}
|
||||
}
|
||||
@@ -466,7 +463,29 @@ impl ConnectionHandler {
|
||||
remote = %self.remote_address
|
||||
)
|
||||
)]
|
||||
pub(crate) async fn handle_stream(&mut self) {
|
||||
pub(crate) async fn handle_connection(&mut self, socket: TcpStream) {
|
||||
let noise_stream = match upgrade_noise_responder(socket, &self.shared.noise_config).await {
|
||||
Ok(noise_stream) => noise_stream,
|
||||
Err(err) => {
|
||||
error!(
|
||||
"Failed to perform Noise handshake with {:?} - {err}",
|
||||
self.remote_address
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
debug!(
|
||||
"Noise responder handshake completed for {:?}",
|
||||
self.remote_address
|
||||
);
|
||||
self.handle_stream(Framed::new(noise_stream, NymCodec))
|
||||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn handle_stream(
|
||||
&mut self,
|
||||
mut mixnet_connection: Framed<Connection<TcpStream>, NymCodec>,
|
||||
) {
|
||||
loop {
|
||||
tokio::select! {
|
||||
biased;
|
||||
@@ -474,7 +493,7 @@ impl ConnectionHandler {
|
||||
trace!("connection handler: received shutdown");
|
||||
break
|
||||
}
|
||||
maybe_framed_nym_packet = self.mixnet_connection.next() => {
|
||||
maybe_framed_nym_packet = mixnet_connection.next() => {
|
||||
match maybe_framed_nym_packet {
|
||||
Some(Ok(packet)) => self.handle_received_nym_packet(packet).await,
|
||||
Some(Err(err)) => {
|
||||
|
||||
@@ -10,6 +10,7 @@ use nym_gateway::node::GatewayStorageError;
|
||||
use nym_mixnet_client::forwarder::{MixForwardingSender, PacketToForward};
|
||||
use nym_node_metrics::mixnet::PacketKind;
|
||||
use nym_node_metrics::NymNodeMetrics;
|
||||
use nym_noise::config::NoiseConfig;
|
||||
use nym_sphinx_forwarding::packet::MixPacket;
|
||||
use nym_sphinx_framing::processing::{
|
||||
MixPacketVersion, MixProcessingResult, MixProcessingResultData, PacketProcessingError,
|
||||
@@ -74,6 +75,9 @@ pub(crate) struct SharedData {
|
||||
// data specific to the final hop (gateway) processing
|
||||
pub(super) final_hop: SharedFinalHopData,
|
||||
|
||||
// for establishing a Noise connection
|
||||
pub(super) noise_config: NoiseConfig,
|
||||
|
||||
pub(super) metrics: NymNodeMetrics,
|
||||
pub(super) shutdown: ShutdownToken,
|
||||
}
|
||||
@@ -86,12 +90,14 @@ fn convert_to_metrics_version(processed: MixPacketVersion) -> PacketKind {
|
||||
}
|
||||
|
||||
impl SharedData {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn new(
|
||||
processing_config: ProcessingConfig,
|
||||
sphinx_keys: ActiveSphinxKeys,
|
||||
replay_protection_filter: ReplayProtectionBloomfilters,
|
||||
mixnet_forwarder: MixForwardingSender,
|
||||
final_hop: SharedFinalHopData,
|
||||
noise_config: NoiseConfig,
|
||||
metrics: NymNodeMetrics,
|
||||
shutdown: ShutdownToken,
|
||||
) -> Self {
|
||||
@@ -101,6 +107,7 @@ impl SharedData {
|
||||
replay_protection_filter,
|
||||
mixnet_forwarder,
|
||||
final_hop,
|
||||
noise_config,
|
||||
metrics,
|
||||
shutdown,
|
||||
}
|
||||
@@ -163,8 +170,9 @@ impl SharedData {
|
||||
match accepted {
|
||||
Ok((socket, remote_addr)) => {
|
||||
debug!("accepted incoming mixnet connection from: {remote_addr}");
|
||||
let mut handler = ConnectionHandler::new(self, socket, remote_addr);
|
||||
let join_handle = tokio::spawn(async move { handler.handle_stream().await });
|
||||
let mut handler = ConnectionHandler::new(self, remote_addr);
|
||||
let join_handle =
|
||||
tokio::spawn(async move { handler.handle_connection(socket).await });
|
||||
self.log_connected_clients();
|
||||
Some(join_handle)
|
||||
}
|
||||
|
||||
@@ -50,6 +50,8 @@ use nym_network_requester::{
|
||||
use nym_node_metrics::events::MetricEventsSender;
|
||||
use nym_node_metrics::NymNodeMetrics;
|
||||
use nym_node_requests::api::v1::node::models::{AnnouncePorts, NodeDescription};
|
||||
use nym_noise::config::{NoiseConfig, NoiseNetworkView};
|
||||
use nym_noise_keys::VersionedNoiseKey;
|
||||
use nym_sphinx_acknowledgements::AckKey;
|
||||
use nym_sphinx_addressing::Recipient;
|
||||
use nym_task::{ShutdownManager, ShutdownToken, TaskClient};
|
||||
@@ -800,16 +802,19 @@ impl NymNode {
|
||||
config.api.v1_config.node.roles.ip_packet_router_enabled = true;
|
||||
}
|
||||
|
||||
let x25519_noise_key = if self.config.mixnet.debug.unsafe_disable_noise {
|
||||
let x25519_versioned_noise_key = if self.config.mixnet.debug.unsafe_disable_noise {
|
||||
None
|
||||
} else {
|
||||
Some(*self.x25519_noise_keys.public_key())
|
||||
Some(VersionedNoiseKey {
|
||||
supported_version: nym_noise::LATEST_NOISE_VERSION,
|
||||
x25519_pubkey: *self.x25519_noise_keys.public_key(),
|
||||
})
|
||||
};
|
||||
|
||||
let app_state = AppState::new(
|
||||
StaticNodeInformation {
|
||||
ed25519_identity_keys: self.ed25519_identity_keys.clone(),
|
||||
x25519_noise_key,
|
||||
x25519_versioned_noise_key,
|
||||
ip_addresses: self.config.host.public_ips.clone(),
|
||||
hostname: self.config.host.hostname.clone(),
|
||||
},
|
||||
@@ -1031,6 +1036,7 @@ impl NymNode {
|
||||
active_clients_store: &ActiveClientsStore,
|
||||
replay_protection_bloomfilter: ReplayProtectionBloomfilters,
|
||||
routing_filter: F,
|
||||
noise_config: NoiseConfig,
|
||||
shutdown: ShutdownToken,
|
||||
) -> Result<(MixForwardingSender, ActiveConnections), NymNodeError>
|
||||
where
|
||||
@@ -1054,6 +1060,7 @@ impl NymNode {
|
||||
);
|
||||
let mixnet_client = nym_mixnet_client::Client::new(
|
||||
mixnet_client_config,
|
||||
noise_config.clone(),
|
||||
self.metrics
|
||||
.network
|
||||
.active_egress_mixnet_connections_counter(),
|
||||
@@ -1080,6 +1087,7 @@ impl NymNode {
|
||||
replay_protection_bloomfilter,
|
||||
mix_packet_sender.clone(),
|
||||
final_hop_data,
|
||||
noise_config,
|
||||
self.metrics.clone(),
|
||||
shutdown,
|
||||
);
|
||||
@@ -1089,10 +1097,18 @@ impl NymNode {
|
||||
}
|
||||
|
||||
pub(crate) async fn run_minimal_mixnet_processing(self) -> Result<(), NymNodeError> {
|
||||
let noise_config = nym_noise::config::NoiseConfig::new(
|
||||
self.x25519_noise_keys.clone(),
|
||||
NoiseNetworkView::new_empty(),
|
||||
self.config.mixnet.debug.initial_connection_timeout,
|
||||
)
|
||||
.with_unsafe_disabled(true);
|
||||
|
||||
self.start_mixnet_listener(
|
||||
&ActiveClientsStore::new(),
|
||||
ReplayProtectionBloomfilters::new_disabled(),
|
||||
OpenFilter,
|
||||
noise_config,
|
||||
self.shutdown_manager.clone_token("mixnet-traffic"),
|
||||
)
|
||||
.await?;
|
||||
@@ -1137,11 +1153,19 @@ impl NymNode {
|
||||
|
||||
let bloomfilters_manager = self.setup_replay_detection().await?;
|
||||
|
||||
let noise_config = nym_noise::config::NoiseConfig::new(
|
||||
self.x25519_noise_keys.clone(),
|
||||
network_refresher.noise_view(),
|
||||
self.config.mixnet.debug.initial_connection_timeout,
|
||||
)
|
||||
.with_unsafe_disabled(self.config.mixnet.debug.unsafe_disable_noise);
|
||||
|
||||
let (mix_packet_sender, active_egress_mixnet_connections) = self
|
||||
.start_mixnet_listener(
|
||||
&active_clients_store,
|
||||
bloomfilters_manager.bloomfilters(),
|
||||
network_refresher.routing_filter(),
|
||||
noise_config,
|
||||
self.shutdown_manager.clone_token("mixnet-traffic"),
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -8,6 +8,7 @@ use async_trait::async_trait;
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
use nym_gateway::node::UserAgent;
|
||||
use nym_node_metrics::prometheus_wrapper::{PrometheusMetric, PROMETHEUS_METRICS};
|
||||
use nym_noise::config::NoiseNetworkView;
|
||||
use nym_task::ShutdownToken;
|
||||
use nym_topology::node::RoutingNode;
|
||||
use nym_topology::{
|
||||
@@ -16,10 +17,10 @@ use nym_topology::{
|
||||
};
|
||||
use nym_validator_client::nym_api::NymApiClientExt;
|
||||
use nym_validator_client::nym_nodes::{
|
||||
NodesByAddressesResponse, SkimmedNode, SkimmedNodesWithMetadata,
|
||||
NodesByAddressesResponse, SemiSkimmedNode, SemiSkimmedNodesWithMetadata,
|
||||
};
|
||||
use nym_validator_client::{NymApiClient, ValidatorClientError};
|
||||
use std::collections::HashSet;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
@@ -63,10 +64,12 @@ impl NodesQuerier {
|
||||
res
|
||||
}
|
||||
|
||||
async fn current_nymnodes(&mut self) -> Result<SkimmedNodesWithMetadata, ValidatorClientError> {
|
||||
async fn current_nymnodes(
|
||||
&mut self,
|
||||
) -> Result<SemiSkimmedNodesWithMetadata, ValidatorClientError> {
|
||||
let res = self
|
||||
.client
|
||||
.get_all_basic_nodes_with_metadata()
|
||||
.get_all_expanded_nodes()
|
||||
.await
|
||||
.inspect_err(|err| error!("failed to get network nodes: {err}"));
|
||||
|
||||
@@ -150,13 +153,19 @@ impl TopologyProvider for CachedTopologyProvider {
|
||||
network_guard.rewarded_set.clone(),
|
||||
Vec::new(),
|
||||
)
|
||||
.with_additional_nodes(network_guard.network_nodes.iter().filter(|node| {
|
||||
if node.supported_roles.mixnode {
|
||||
node.performance.round_to_integer() >= self.min_mix_performance
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}));
|
||||
.with_additional_nodes(
|
||||
network_guard
|
||||
.network_nodes
|
||||
.iter()
|
||||
.map(|node| &node.basic)
|
||||
.filter(|node| {
|
||||
if node.supported_roles.mixnode {
|
||||
node.performance.round_to_integer() >= self.min_mix_performance
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
if !topology.has_node(self.gateway_node.identity_key) {
|
||||
debug!("{self_node} didn't exist in topology. inserting it.",);
|
||||
@@ -188,7 +197,7 @@ impl CachedNetwork {
|
||||
struct CachedNetworkInner {
|
||||
rewarded_set: EpochRewardedSet,
|
||||
topology_metadata: NymTopologyMetadata,
|
||||
network_nodes: Vec<SkimmedNode>,
|
||||
network_nodes: Vec<SemiSkimmedNode>,
|
||||
}
|
||||
|
||||
pub struct NetworkRefresher {
|
||||
@@ -199,6 +208,7 @@ pub struct NetworkRefresher {
|
||||
|
||||
network: CachedNetwork,
|
||||
routing_filter: NetworkRoutingFilter,
|
||||
noise_view: NoiseNetworkView,
|
||||
}
|
||||
|
||||
impl NetworkRefresher {
|
||||
@@ -226,6 +236,7 @@ impl NetworkRefresher {
|
||||
shutdown_token,
|
||||
network: CachedNetwork::new_empty(),
|
||||
routing_filter: NetworkRoutingFilter::new_empty(testnet),
|
||||
noise_view: NoiseNetworkView::new_empty(),
|
||||
};
|
||||
|
||||
this.obtain_initial_network().await?;
|
||||
@@ -282,7 +293,7 @@ impl NetworkRefresher {
|
||||
// collect all known/allowed nodes information
|
||||
let known_nodes = nodes
|
||||
.iter()
|
||||
.flat_map(|n| n.ip_addresses.iter())
|
||||
.flat_map(|n| n.basic.ip_addresses.iter())
|
||||
.copied()
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
@@ -305,6 +316,22 @@ impl NetworkRefresher {
|
||||
self.routing_filter.resolved.swap_denied(current_denied);
|
||||
self.routing_filter.pending.clear().await;
|
||||
|
||||
//update noise Noise Nodes
|
||||
let noise_nodes = nodes
|
||||
.iter()
|
||||
.filter(|n| n.x25519_noise_versioned_key.is_some())
|
||||
.flat_map(|n| {
|
||||
n.basic.ip_addresses.iter().map(|ip_addr| {
|
||||
(
|
||||
SocketAddr::new(*ip_addr, n.basic.mix_port),
|
||||
#[allow(clippy::unwrap_used)]
|
||||
n.x25519_noise_versioned_key.unwrap(), // SAFETY : we filtered out nodes where this option can be None
|
||||
)
|
||||
})
|
||||
})
|
||||
.collect::<HashMap<_, _>>();
|
||||
self.noise_view.swap_view(noise_nodes);
|
||||
|
||||
let mut network_guard = self.network.inner.write().await;
|
||||
network_guard.topology_metadata =
|
||||
NymTopologyMetadata::new(metadata.rotation_id, metadata.absolute_epoch_id);
|
||||
@@ -340,6 +367,10 @@ impl NetworkRefresher {
|
||||
self.network.clone()
|
||||
}
|
||||
|
||||
pub(crate) fn noise_view(&self) -> NoiseNetworkView {
|
||||
self.noise_view.clone()
|
||||
}
|
||||
|
||||
pub(crate) async fn run(&mut self) {
|
||||
let mut full_refresh_interval = interval(self.full_refresh_interval);
|
||||
full_refresh_interval.reset();
|
||||
|
||||
Reference in New Issue
Block a user