Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1c9a4b803e | |||
| a0fa3b9b5f | |||
| 00d47958a7 | |||
| 00600ddeeb | |||
| ba2ede65ac | |||
| 4e6694baf0 |
@@ -19,7 +19,7 @@ jobs:
|
|||||||
|
|
||||||
outputs:
|
outputs:
|
||||||
release_id: ${{ steps.create-release.outputs.id }}
|
release_id: ${{ steps.create-release.outputs.id }}
|
||||||
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].created_at }}
|
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }}
|
||||||
version: ${{ steps.release-info.outputs.version }}
|
version: ${{ steps.release-info.outputs.version }}
|
||||||
filename: ${{ steps.release-info.outputs.filename }}
|
filename: ${{ steps.release-info.outputs.filename }}
|
||||||
file_hash: ${{ steps.release-info.outputs.file_hash }}
|
file_hash: ${{ steps.release-info.outputs.file_hash }}
|
||||||
@@ -93,6 +93,18 @@ jobs:
|
|||||||
if: ${{ always() }}
|
if: ${{ always() }}
|
||||||
run: |
|
run: |
|
||||||
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
|
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
|
||||||
|
|
||||||
|
- name: debug print
|
||||||
|
run: |
|
||||||
|
echo "Release ID: ${{ steps.create-release.outputs.id }}"
|
||||||
|
echo "Release Assets: ${{ steps.create-release.outputs.assets }}"
|
||||||
|
|
||||||
|
# this is failing somehow, let's see what's being outputted
|
||||||
|
- name: debug print 2
|
||||||
|
run: |
|
||||||
|
echo "Release ID: ${{ steps.create-release.outputs.id }}"
|
||||||
|
echo "Release Assets: ${{ steps.create-release.outputs.assets }}"
|
||||||
|
|
||||||
- id: create-release
|
- id: create-release
|
||||||
name: Upload to release based on tag name
|
name: Upload to release based on tag name
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v1
|
||||||
|
|||||||
@@ -4,6 +4,22 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [2023.5-rolo] (2023-11-28)
|
||||||
|
|
||||||
|
- Gateway won't open websocket listener until embedded Network Requester becomes available ([#4166])
|
||||||
|
- Feature/gateway described nr ([#4147])
|
||||||
|
- Bugfix/prerelease versionbump ([#4145])
|
||||||
|
- returning 'nil' for non-existing origin as opposed to an empty string ([#4135])
|
||||||
|
- using performance^20 when calculating active set selection weight ([#4126])
|
||||||
|
- Change default http API timeout from 3s to 10s ([#4117])
|
||||||
|
|
||||||
|
[#4166]: https://github.com/nymtech/nym/issues/4166
|
||||||
|
[#4147]: https://github.com/nymtech/nym/pull/4147
|
||||||
|
[#4145]: https://github.com/nymtech/nym/pull/4145
|
||||||
|
[#4135]: https://github.com/nymtech/nym/pull/4135
|
||||||
|
[#4126]: https://github.com/nymtech/nym/pull/4126
|
||||||
|
[#4117]: https://github.com/nymtech/nym/pull/4117
|
||||||
|
|
||||||
## [2023.nyxd-upgrade] (2023-11-22)
|
## [2023.nyxd-upgrade] (2023-11-22)
|
||||||
|
|
||||||
- Chore/nyxd 043 upgrade ([#3968])
|
- Chore/nyxd 043 upgrade ([#3968])
|
||||||
|
|||||||
Generated
+9
-13
@@ -2929,7 +2929,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "explorer-api"
|
name = "explorer-api"
|
||||||
version = "1.1.31"
|
version = "1.1.32"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap 4.4.7",
|
"clap 4.4.7",
|
||||||
@@ -5905,7 +5905,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-api"
|
name = "nym-api"
|
||||||
version = "1.1.33"
|
version = "1.1.34"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-web",
|
"actix-web",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
@@ -6055,7 +6055,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-cli"
|
name = "nym-cli"
|
||||||
version = "1.1.32"
|
version = "1.1.33"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"base64 0.13.1",
|
"base64 0.13.1",
|
||||||
@@ -6128,7 +6128,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-client"
|
name = "nym-client"
|
||||||
version = "1.1.31"
|
version = "1.1.32"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap 4.4.7",
|
"clap 4.4.7",
|
||||||
"dirs 4.0.0",
|
"dirs 4.0.0",
|
||||||
@@ -6472,7 +6472,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-gateway"
|
name = "nym-gateway"
|
||||||
version = "1.1.31"
|
version = "1.1.32"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@@ -6608,9 +6608,7 @@ dependencies = [
|
|||||||
"bincode",
|
"bincode",
|
||||||
"bytes",
|
"bytes",
|
||||||
"nym-sphinx",
|
"nym-sphinx",
|
||||||
"rand 0.8.5",
|
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -6619,7 +6617,6 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bincode",
|
"bincode",
|
||||||
"bytes",
|
"bytes",
|
||||||
"dashmap",
|
|
||||||
"etherparse",
|
"etherparse",
|
||||||
"futures",
|
"futures",
|
||||||
"log",
|
"log",
|
||||||
@@ -6636,7 +6633,6 @@ dependencies = [
|
|||||||
"nym-tun",
|
"nym-tun",
|
||||||
"nym-wireguard",
|
"nym-wireguard",
|
||||||
"nym-wireguard-types",
|
"nym-wireguard-types",
|
||||||
"rand 0.8.5",
|
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@@ -6681,7 +6677,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-mixnode"
|
name = "nym-mixnode"
|
||||||
version = "1.1.33"
|
version = "1.1.34"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"axum",
|
"axum",
|
||||||
@@ -6801,7 +6797,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-network-requester"
|
name = "nym-network-requester"
|
||||||
version = "1.1.31"
|
version = "1.1.32"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-file-watcher",
|
"async-file-watcher",
|
||||||
@@ -6849,7 +6845,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-network-statistics"
|
name = "nym-network-statistics"
|
||||||
version = "1.1.31"
|
version = "1.1.32"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dirs 4.0.0",
|
"dirs 4.0.0",
|
||||||
"log",
|
"log",
|
||||||
@@ -7094,7 +7090,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-socks5-client"
|
name = "nym-socks5-client"
|
||||||
version = "1.1.31"
|
version = "1.1.32"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap 4.4.7",
|
"clap 4.4.7",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nym-client"
|
name = "nym-client"
|
||||||
version = "1.1.31"
|
version = "1.1.32"
|
||||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||||
description = "Implementation of the Nym Client"
|
description = "Implementation of the Nym Client"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nym-socks5-client"
|
name = "nym-socks5-client"
|
||||||
version = "1.1.31"
|
version = "1.1.32"
|
||||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||||
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
|
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|||||||
@@ -366,7 +366,11 @@ pub fn creating_proof_of_chunking_for_100_parties(c: &mut Criterion) {
|
|||||||
.map(|&node_index| polynomial.evaluate_at(&Scalar::from(node_index)).into())
|
.map(|&node_index| polynomial.evaluate_at(&Scalar::from(node_index)).into())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let remote_share_key_pairs = shares.iter().zip(receivers.values()).collect::<Vec<_>>();
|
let remote_share_key_pairs = shares
|
||||||
|
.iter()
|
||||||
|
.zip(receivers.values())
|
||||||
|
.map(|(share, key)| (share, key))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
let ordered_public_keys = receivers.values().copied().collect::<Vec<_>>();
|
let ordered_public_keys = receivers.values().copied().collect::<Vec<_>>();
|
||||||
|
|
||||||
let (ciphertexts, hazmat) = encrypt_shares(&remote_share_key_pairs, ¶ms, &mut rng);
|
let (ciphertexts, hazmat) = encrypt_shares(&remote_share_key_pairs, ¶ms, &mut rng);
|
||||||
@@ -396,7 +400,11 @@ pub fn verifying_proof_of_chunking_for_100_parties(c: &mut Criterion) {
|
|||||||
.map(|&node_index| polynomial.evaluate_at(&Scalar::from(node_index)).into())
|
.map(|&node_index| polynomial.evaluate_at(&Scalar::from(node_index)).into())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let remote_share_key_pairs = shares.iter().zip(receivers.values()).collect::<Vec<_>>();
|
let remote_share_key_pairs = shares
|
||||||
|
.iter()
|
||||||
|
.zip(receivers.values())
|
||||||
|
.map(|(share, key)| (share, key))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
let ordered_public_keys = receivers.values().copied().collect::<Vec<_>>();
|
let ordered_public_keys = receivers.values().copied().collect::<Vec<_>>();
|
||||||
|
|
||||||
let (ciphertexts, hazmat) = encrypt_shares(&remote_share_key_pairs, ¶ms, &mut rng);
|
let (ciphertexts, hazmat) = encrypt_shares(&remote_share_key_pairs, ¶ms, &mut rng);
|
||||||
@@ -428,7 +436,11 @@ pub fn creating_proof_of_secret_sharing_for_100_parties(c: &mut Criterion) {
|
|||||||
.map(|&node_index| polynomial.evaluate_at(&Scalar::from(node_index)).into())
|
.map(|&node_index| polynomial.evaluate_at(&Scalar::from(node_index)).into())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let remote_share_key_pairs = shares.iter().zip(receivers.values()).collect::<Vec<_>>();
|
let remote_share_key_pairs = shares
|
||||||
|
.iter()
|
||||||
|
.zip(receivers.values())
|
||||||
|
.map(|(share, key)| (share, key))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let (ciphertexts, hazmat) = encrypt_shares(&remote_share_key_pairs, ¶ms, &mut rng);
|
let (ciphertexts, hazmat) = encrypt_shares(&remote_share_key_pairs, ¶ms, &mut rng);
|
||||||
|
|
||||||
@@ -466,7 +478,11 @@ pub fn verifying_proof_of_secret_sharing_for_100_parties(c: &mut Criterion) {
|
|||||||
.map(|&node_index| polynomial.evaluate_at(&Scalar::from(node_index)).into())
|
.map(|&node_index| polynomial.evaluate_at(&Scalar::from(node_index)).into())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let remote_share_key_pairs = shares.iter().zip(receivers.values()).collect::<Vec<_>>();
|
let remote_share_key_pairs = shares
|
||||||
|
.iter()
|
||||||
|
.zip(receivers.values())
|
||||||
|
.map(|(share, key)| (share, key))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let (ciphertexts, hazmat) = encrypt_shares(&remote_share_key_pairs, ¶ms, &mut rng);
|
let (ciphertexts, hazmat) = encrypt_shares(&remote_share_key_pairs, ¶ms, &mut rng);
|
||||||
|
|
||||||
@@ -529,7 +545,11 @@ pub fn share_encryption_100(c: &mut Criterion) {
|
|||||||
.map(|&node_index| polynomial.evaluate_at(&Scalar::from(node_index)).into())
|
.map(|&node_index| polynomial.evaluate_at(&Scalar::from(node_index)).into())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let remote_share_key_pairs = shares.iter().zip(receivers.values()).collect::<Vec<_>>();
|
let remote_share_key_pairs = shares
|
||||||
|
.iter()
|
||||||
|
.zip(receivers.values())
|
||||||
|
.map(|(share, key)| (share, key))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
c.bench_function("100 shares encryption", |b| {
|
c.bench_function("100 shares encryption", |b| {
|
||||||
b.iter(|| black_box(encrypt_shares(&remote_share_key_pairs, ¶ms, &mut rng)))
|
b.iter(|| black_box(encrypt_shares(&remote_share_key_pairs, ¶ms, &mut rng)))
|
||||||
|
|||||||
@@ -14,6 +14,4 @@ license.workspace = true
|
|||||||
bincode = "1.3.3"
|
bincode = "1.3.3"
|
||||||
bytes = "1.5.0"
|
bytes = "1.5.0"
|
||||||
nym-sphinx = { path = "../nymsphinx" }
|
nym-sphinx = { path = "../nymsphinx" }
|
||||||
rand = "0.8.5"
|
|
||||||
serde = { workspace = true, features = ["derive"] }
|
serde = { workspace = true, features = ["derive"] }
|
||||||
thiserror = { workspace = true }
|
|
||||||
|
|||||||
@@ -1,308 +1,35 @@
|
|||||||
use std::net::IpAddr;
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
|
pub struct TaggedIpPacket {
|
||||||
use nym_sphinx::addressing::clients::Recipient;
|
pub packet: bytes::Bytes,
|
||||||
use serde::{Deserialize, Serialize};
|
pub return_address: nym_sphinx::addressing::clients::Recipient,
|
||||||
|
pub return_mix_hops: Option<u8>,
|
||||||
pub const CURRENT_VERSION: u8 = 1;
|
// pub return_mix_delays: Option<f64>,
|
||||||
|
|
||||||
fn generate_random() -> u64 {
|
|
||||||
use rand::RngCore;
|
|
||||||
let mut rng = rand::rngs::OsRng;
|
|
||||||
rng.next_u64()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
impl TaggedIpPacket {
|
||||||
pub struct IpPacketRequest {
|
pub fn new(
|
||||||
pub version: u8,
|
packet: bytes::Bytes,
|
||||||
pub data: IpPacketRequestData,
|
return_address: nym_sphinx::addressing::clients::Recipient,
|
||||||
}
|
return_mix_hops: Option<u8>,
|
||||||
|
) -> Self {
|
||||||
impl IpPacketRequest {
|
TaggedIpPacket {
|
||||||
pub fn new_static_connect_request(
|
packet,
|
||||||
ip: IpAddr,
|
return_address,
|
||||||
reply_to: Recipient,
|
return_mix_hops,
|
||||||
reply_to_hops: Option<u8>,
|
|
||||||
reply_to_avg_mix_delays: Option<f64>,
|
|
||||||
) -> (Self, u64) {
|
|
||||||
let request_id = generate_random();
|
|
||||||
(
|
|
||||||
Self {
|
|
||||||
version: CURRENT_VERSION,
|
|
||||||
data: IpPacketRequestData::StaticConnect(StaticConnectRequest {
|
|
||||||
request_id,
|
|
||||||
ip,
|
|
||||||
reply_to,
|
|
||||||
reply_to_hops,
|
|
||||||
reply_to_avg_mix_delays,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
request_id,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_dynamic_connect_request(
|
|
||||||
reply_to: Recipient,
|
|
||||||
reply_to_hops: Option<u8>,
|
|
||||||
reply_to_avg_mix_delays: Option<f64>,
|
|
||||||
) -> (Self, u64) {
|
|
||||||
let request_id = generate_random();
|
|
||||||
(
|
|
||||||
Self {
|
|
||||||
version: CURRENT_VERSION,
|
|
||||||
data: IpPacketRequestData::DynamicConnect(DynamicConnectRequest {
|
|
||||||
request_id,
|
|
||||||
reply_to,
|
|
||||||
reply_to_hops,
|
|
||||||
reply_to_avg_mix_delays,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
request_id,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_ip_packet(ip_packet: bytes::Bytes) -> Self {
|
|
||||||
Self {
|
|
||||||
version: CURRENT_VERSION,
|
|
||||||
data: IpPacketRequestData::Data(DataRequest { ip_packet }),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn id(&self) -> Option<u64> {
|
|
||||||
match &self.data {
|
|
||||||
IpPacketRequestData::StaticConnect(request) => Some(request.request_id),
|
|
||||||
IpPacketRequestData::DynamicConnect(request) => Some(request.request_id),
|
|
||||||
IpPacketRequestData::Data(_) => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn recipient(&self) -> Option<&Recipient> {
|
|
||||||
match &self.data {
|
|
||||||
IpPacketRequestData::StaticConnect(request) => Some(&request.reply_to),
|
|
||||||
IpPacketRequestData::DynamicConnect(request) => Some(&request.reply_to),
|
|
||||||
IpPacketRequestData::Data(_) => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_bytes(&self) -> Result<Vec<u8>, bincode::Error> {
|
|
||||||
use bincode::Options;
|
|
||||||
make_bincode_serializer().serialize(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_reconstructed_message(
|
pub fn from_reconstructed_message(
|
||||||
message: &nym_sphinx::receiver::ReconstructedMessage,
|
message: &nym_sphinx::receiver::ReconstructedMessage,
|
||||||
) -> Result<Self, bincode::Error> {
|
) -> Result<Self, bincode::Error> {
|
||||||
use bincode::Options;
|
use bincode::Options;
|
||||||
make_bincode_serializer().deserialize(&message.message)
|
make_bincode_serializer().deserialize(&message.message)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::large_enum_variant)]
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
||||||
pub enum IpPacketRequestData {
|
|
||||||
StaticConnect(StaticConnectRequest),
|
|
||||||
DynamicConnect(DynamicConnectRequest),
|
|
||||||
Data(DataRequest),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
||||||
pub struct StaticConnectRequest {
|
|
||||||
pub request_id: u64,
|
|
||||||
pub ip: IpAddr,
|
|
||||||
pub reply_to: Recipient,
|
|
||||||
pub reply_to_hops: Option<u8>,
|
|
||||||
pub reply_to_avg_mix_delays: Option<f64>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
||||||
pub struct DynamicConnectRequest {
|
|
||||||
pub request_id: u64,
|
|
||||||
pub reply_to: Recipient,
|
|
||||||
pub reply_to_hops: Option<u8>,
|
|
||||||
pub reply_to_avg_mix_delays: Option<f64>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
||||||
pub struct DataRequest {
|
|
||||||
pub ip_packet: bytes::Bytes,
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
pub struct IpPacketResponse {
|
|
||||||
pub version: u8,
|
|
||||||
pub data: IpPacketResponseData,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IpPacketResponse {
|
|
||||||
pub fn new_static_connect_success(request_id: u64, reply_to: Recipient) -> Self {
|
|
||||||
Self {
|
|
||||||
version: CURRENT_VERSION,
|
|
||||||
data: IpPacketResponseData::StaticConnect(StaticConnectResponse {
|
|
||||||
request_id,
|
|
||||||
reply_to,
|
|
||||||
reply: StaticConnectResponseReply::Success,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_static_connect_failure(
|
|
||||||
request_id: u64,
|
|
||||||
reply_to: Recipient,
|
|
||||||
reason: StaticConnectFailureReason,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
version: CURRENT_VERSION,
|
|
||||||
data: IpPacketResponseData::StaticConnect(StaticConnectResponse {
|
|
||||||
request_id,
|
|
||||||
reply_to,
|
|
||||||
reply: StaticConnectResponseReply::Failure(reason),
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_dynamic_connect_success(request_id: u64, reply_to: Recipient, ip: IpAddr) -> Self {
|
|
||||||
Self {
|
|
||||||
version: CURRENT_VERSION,
|
|
||||||
data: IpPacketResponseData::DynamicConnect(DynamicConnectResponse {
|
|
||||||
request_id,
|
|
||||||
reply_to,
|
|
||||||
reply: DynamicConnectResponseReply::Success(DynamicConnectSuccess { ip }),
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_dynamic_connect_failure(
|
|
||||||
request_id: u64,
|
|
||||||
reply_to: Recipient,
|
|
||||||
reason: DynamicConnectFailureReason,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
version: CURRENT_VERSION,
|
|
||||||
data: IpPacketResponseData::DynamicConnect(DynamicConnectResponse {
|
|
||||||
request_id,
|
|
||||||
reply_to,
|
|
||||||
reply: DynamicConnectResponseReply::Failure(reason),
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_ip_packet(ip_packet: bytes::Bytes) -> Self {
|
|
||||||
Self {
|
|
||||||
version: CURRENT_VERSION,
|
|
||||||
data: IpPacketResponseData::Data(DataResponse { ip_packet }),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn id(&self) -> Option<u64> {
|
|
||||||
match &self.data {
|
|
||||||
IpPacketResponseData::StaticConnect(response) => Some(response.request_id),
|
|
||||||
IpPacketResponseData::DynamicConnect(response) => Some(response.request_id),
|
|
||||||
IpPacketResponseData::Data(_) => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn recipient(&self) -> Option<&Recipient> {
|
|
||||||
match &self.data {
|
|
||||||
IpPacketResponseData::StaticConnect(response) => Some(&response.reply_to),
|
|
||||||
IpPacketResponseData::DynamicConnect(response) => Some(&response.reply_to),
|
|
||||||
IpPacketResponseData::Data(_) => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_bytes(&self) -> Result<Vec<u8>, bincode::Error> {
|
pub fn to_bytes(&self) -> Result<Vec<u8>, bincode::Error> {
|
||||||
use bincode::Options;
|
use bincode::Options;
|
||||||
make_bincode_serializer().serialize(self)
|
make_bincode_serializer().serialize(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_reconstructed_message(
|
|
||||||
message: &nym_sphinx::receiver::ReconstructedMessage,
|
|
||||||
) -> Result<Self, bincode::Error> {
|
|
||||||
use bincode::Options;
|
|
||||||
make_bincode_serializer().deserialize(&message.message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::large_enum_variant)]
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
pub enum IpPacketResponseData {
|
|
||||||
StaticConnect(StaticConnectResponse),
|
|
||||||
DynamicConnect(DynamicConnectResponse),
|
|
||||||
Data(DataResponse),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
pub struct StaticConnectResponse {
|
|
||||||
pub request_id: u64,
|
|
||||||
pub reply_to: Recipient,
|
|
||||||
pub reply: StaticConnectResponseReply,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
pub enum StaticConnectResponseReply {
|
|
||||||
Success,
|
|
||||||
Failure(StaticConnectFailureReason),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StaticConnectResponseReply {
|
|
||||||
pub fn is_success(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
StaticConnectResponseReply::Success => true,
|
|
||||||
StaticConnectResponseReply::Failure(_) => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, thiserror::Error)]
|
|
||||||
pub enum StaticConnectFailureReason {
|
|
||||||
#[error("requested ip address is already in use")]
|
|
||||||
RequestedIpAlreadyInUse,
|
|
||||||
#[error("requested nym-address is already in use")]
|
|
||||||
RequestedNymAddressAlreadyInUse,
|
|
||||||
#[error("{0}")]
|
|
||||||
Other(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
pub struct DynamicConnectResponse {
|
|
||||||
pub request_id: u64,
|
|
||||||
pub reply_to: Recipient,
|
|
||||||
pub reply: DynamicConnectResponseReply,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
pub enum DynamicConnectResponseReply {
|
|
||||||
Success(DynamicConnectSuccess),
|
|
||||||
Failure(DynamicConnectFailureReason),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DynamicConnectResponseReply {
|
|
||||||
pub fn is_success(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
DynamicConnectResponseReply::Success(_) => true,
|
|
||||||
DynamicConnectResponseReply::Failure(_) => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
pub struct DynamicConnectSuccess {
|
|
||||||
pub ip: IpAddr,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, thiserror::Error)]
|
|
||||||
pub enum DynamicConnectFailureReason {
|
|
||||||
#[error("requested nym-address is already in use")]
|
|
||||||
RequestedNymAddressAlreadyInUse,
|
|
||||||
#[error("no available ip address")]
|
|
||||||
NoAvailableIp,
|
|
||||||
#[error("{0}")]
|
|
||||||
Other(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
pub struct DataResponse {
|
|
||||||
pub ip_packet: bytes::Bytes,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_bincode_serializer() -> impl bincode::Options {
|
fn make_bincode_serializer() -> impl bincode::Options {
|
||||||
@@ -311,63 +38,3 @@ fn make_bincode_serializer() -> impl bincode::Options {
|
|||||||
.with_big_endian()
|
.with_big_endian()
|
||||||
.with_varint_encoding()
|
.with_varint_encoding()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn check_size_of_request() {
|
|
||||||
let connect = IpPacketRequest {
|
|
||||||
version: 4,
|
|
||||||
data: IpPacketRequestData::StaticConnect(
|
|
||||||
StaticConnectRequest {
|
|
||||||
request_id: 123,
|
|
||||||
ip: IpAddr::from([10, 0, 0, 1]),
|
|
||||||
reply_to: Recipient::try_from_base58_string("D1rrpsysCGCYXy9saP8y3kmNpGtJZUXN9SvFoUcqAsM9.9Ssso1ea5NfkbMASdiseDSjTN1fSWda5SgEVjdSN4CvV@GJqd3ZxpXWSNxTfx7B1pPtswpetH4LnJdFeLeuY5KUuN").unwrap(),
|
|
||||||
reply_to_hops: None,
|
|
||||||
reply_to_avg_mix_delays: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
};
|
|
||||||
assert_eq!(connect.to_bytes().unwrap().len(), 107);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn check_size_of_data() {
|
|
||||||
let data = IpPacketRequest {
|
|
||||||
version: 4,
|
|
||||||
data: IpPacketRequestData::Data(DataRequest {
|
|
||||||
ip_packet: bytes::Bytes::from(vec![1u8; 32]),
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
assert_eq!(data.to_bytes().unwrap().len(), 35);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn serialize_and_deserialize_data_request() {
|
|
||||||
let data = IpPacketRequest {
|
|
||||||
version: 4,
|
|
||||||
data: IpPacketRequestData::Data(DataRequest {
|
|
||||||
ip_packet: bytes::Bytes::from(vec![1, 2, 4, 2, 5]),
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
let serialized = data.to_bytes().unwrap();
|
|
||||||
let deserialized = IpPacketRequest::from_reconstructed_message(
|
|
||||||
&nym_sphinx::receiver::ReconstructedMessage {
|
|
||||||
message: serialized,
|
|
||||||
sender_tag: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(deserialized.version, 4);
|
|
||||||
assert_eq!(
|
|
||||||
deserialized.data,
|
|
||||||
IpPacketRequestData::Data(DataRequest {
|
|
||||||
ip_packet: bytes::Bytes::from(vec![1, 2, 4, 2, 5]),
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -6,10 +6,9 @@ use criterion::{criterion_group, criterion_main, Criterion};
|
|||||||
use ff::Field;
|
use ff::Field;
|
||||||
use group::{Curve, Group};
|
use group::{Curve, Group};
|
||||||
use nym_coconut::{
|
use nym_coconut::{
|
||||||
aggregate_signature_shares, aggregate_verification_keys, blind_sign, prepare_blind_sign,
|
aggregate_signature_shares, aggregate_verification_keys, blind_sign, elgamal_keygen,
|
||||||
prove_bandwidth_credential, setup, ttp_keygen, verify_credential,
|
prepare_blind_sign, prove_bandwidth_credential, setup, ttp_keygen, verify_credential,
|
||||||
verify_partial_blind_signature, Attribute, BlindedSignature, Parameters, Signature,
|
Attribute, BlindedSignature, Parameters, Signature, SignatureShare, VerificationKey,
|
||||||
SignatureShare, VerificationKey,
|
|
||||||
};
|
};
|
||||||
use rand::seq::SliceRandom;
|
use rand::seq::SliceRandom;
|
||||||
use std::ops::Neg;
|
use std::ops::Neg;
|
||||||
@@ -176,6 +175,8 @@ fn bench_coconut(c: &mut Criterion) {
|
|||||||
let binding_number = params.random_scalar();
|
let binding_number = params.random_scalar();
|
||||||
let private_attributes = vec![serial_number, binding_number];
|
let private_attributes = vec![serial_number, binding_number];
|
||||||
|
|
||||||
|
let _elgamal_keypair = elgamal_keygen(¶ms);
|
||||||
|
|
||||||
// The prepare blind sign is performed by the user
|
// The prepare blind sign is performed by the user
|
||||||
let (pedersen_commitments_openings, blind_sign_request) =
|
let (pedersen_commitments_openings, blind_sign_request) =
|
||||||
prepare_blind_sign(¶ms, &private_attributes, &public_attributes).unwrap();
|
prepare_blind_sign(¶ms, &private_attributes, &public_attributes).unwrap();
|
||||||
@@ -241,29 +242,6 @@ fn bench_coconut(c: &mut Criterion) {
|
|||||||
.map(|keypair| keypair.verification_key())
|
.map(|keypair| keypair.verification_key())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// verify a random partial blind signature
|
|
||||||
let rand_idx = 1;
|
|
||||||
let random_blind_signature = blinded_signatures.get(rand_idx).unwrap();
|
|
||||||
let partial_verification_key = verification_keys.get(rand_idx).unwrap();
|
|
||||||
|
|
||||||
group.bench_function(
|
|
||||||
&format!(
|
|
||||||
"verify_partial_blind_signature_{}_private_attributes_{}_public_attributes",
|
|
||||||
case.num_private_attrs, case.num_public_attrs
|
|
||||||
),
|
|
||||||
|b| {
|
|
||||||
b.iter(|| {
|
|
||||||
verify_partial_blind_signature(
|
|
||||||
¶ms,
|
|
||||||
&blind_sign_request,
|
|
||||||
&public_attributes,
|
|
||||||
random_blind_signature,
|
|
||||||
partial_verification_key,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// Lets bench worse case, ie aggregating all
|
// Lets bench worse case, ie aggregating all
|
||||||
let indices: Vec<u64> = (1..=case.num_authorities).collect();
|
let indices: Vec<u64> = (1..=case.num_authorities).collect();
|
||||||
// aggregate verification keys
|
// aggregate verification keys
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ pub use scheme::aggregation::aggregate_signature_shares;
|
|||||||
pub use scheme::aggregation::aggregate_verification_keys;
|
pub use scheme::aggregation::aggregate_verification_keys;
|
||||||
pub use scheme::issuance::blind_sign;
|
pub use scheme::issuance::blind_sign;
|
||||||
pub use scheme::issuance::prepare_blind_sign;
|
pub use scheme::issuance::prepare_blind_sign;
|
||||||
pub use scheme::issuance::verify_partial_blind_signature;
|
|
||||||
pub use scheme::issuance::BlindSignRequest;
|
pub use scheme::issuance::BlindSignRequest;
|
||||||
pub use scheme::keygen::ttp_keygen;
|
pub use scheme::keygen::ttp_keygen;
|
||||||
pub use scheme::keygen::KeyPair;
|
pub use scheme::keygen::KeyPair;
|
||||||
|
|||||||
@@ -3,14 +3,12 @@
|
|||||||
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::ops::Neg;
|
|
||||||
|
|
||||||
use bls12_381::{multi_miller_loop, G1Affine, G1Projective, G2Prepared, Scalar};
|
use bls12_381::{G1Affine, G1Projective, Scalar};
|
||||||
use group::{Curve, Group, GroupEncoding};
|
use group::{Curve, GroupEncoding};
|
||||||
|
|
||||||
use crate::error::{CoconutError, Result};
|
use crate::error::{CoconutError, Result};
|
||||||
use crate::proofs::ProofCmCs;
|
use crate::proofs::ProofCmCs;
|
||||||
use crate::scheme::keygen::VerificationKey;
|
|
||||||
use crate::scheme::setup::Parameters;
|
use crate::scheme::setup::Parameters;
|
||||||
use crate::scheme::BlindedSignature;
|
use crate::scheme::BlindedSignature;
|
||||||
use crate::scheme::SecretKey;
|
use crate::scheme::SecretKey;
|
||||||
@@ -320,96 +318,6 @@ pub fn blind_sign(
|
|||||||
Ok(BlindedSignature(h, sig))
|
Ok(BlindedSignature(h, sig))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Verifies a partial blind signature using the provided parameters and validator's verification key.
|
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
///
|
|
||||||
/// * `params` - A reference to the cryptographic parameters.
|
|
||||||
/// * `blind_sign_request` - A reference to the blind signature request signed by the client.
|
|
||||||
/// * `public_attributes` - A reference to the public attributes included in the client's request.
|
|
||||||
/// * `blind_sig` - A reference to the issued partial blinded signature to be verified.
|
|
||||||
/// * `partial_verification_key` - A reference to the validator's partial verification key.
|
|
||||||
///
|
|
||||||
/// # Returns
|
|
||||||
///
|
|
||||||
/// A boolean indicating whether the partial blind signature is valid (`true`) or not (`false`).
|
|
||||||
///
|
|
||||||
/// # Remarks
|
|
||||||
///
|
|
||||||
/// This function verifies the correctness and validity of a partial blind signature using
|
|
||||||
/// the provided cryptographic parameters, blind signature request, blinded signature,
|
|
||||||
/// and partial verification key.
|
|
||||||
/// It calculates pairings based on the provided values and checks whether the partial blind signature
|
|
||||||
/// is consistent with the verification key and commitments in the blind signature request.
|
|
||||||
/// The function returns `true` if the partial blind signature is valid, and `false` otherwise.
|
|
||||||
pub fn verify_partial_blind_signature(
|
|
||||||
params: &Parameters,
|
|
||||||
blind_sign_request: &BlindSignRequest,
|
|
||||||
public_attributes: &[Attribute],
|
|
||||||
blind_sig: &BlindedSignature,
|
|
||||||
partial_verification_key: &VerificationKey,
|
|
||||||
) -> bool {
|
|
||||||
let num_private_attributes = blind_sign_request.private_attributes_commitments.len();
|
|
||||||
if num_private_attributes + public_attributes.len() > partial_verification_key.beta_g2.len() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: we're losing some memory here due to extra allocation,
|
|
||||||
// but worst-case scenario (given SANE amount of attributes), it's just few kb at most
|
|
||||||
let c_neg = blind_sig.1.to_affine().neg();
|
|
||||||
let g2_prep = params.prepared_miller_g2();
|
|
||||||
|
|
||||||
let mut terms = vec![
|
|
||||||
// (c^{-1}, g2)
|
|
||||||
(c_neg, g2_prep.clone()),
|
|
||||||
// (s, alpha)
|
|
||||||
(
|
|
||||||
blind_sig.0.to_affine(),
|
|
||||||
G2Prepared::from(partial_verification_key.alpha.to_affine()),
|
|
||||||
),
|
|
||||||
];
|
|
||||||
|
|
||||||
// for each private attribute, add (cm_i, beta_i) to the miller terms
|
|
||||||
for (private_attr_commit, beta_g2) in blind_sign_request
|
|
||||||
.private_attributes_commitments
|
|
||||||
.iter()
|
|
||||||
.zip(&partial_verification_key.beta_g2)
|
|
||||||
{
|
|
||||||
// (cm_i, beta_i)
|
|
||||||
terms.push((
|
|
||||||
private_attr_commit.to_affine(),
|
|
||||||
G2Prepared::from(beta_g2.to_affine()),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
// for each public attribute, add (s^pub_j, beta_{priv + j}) to the miller terms
|
|
||||||
for (pub_attr, beta_g2) in public_attributes.iter().zip(
|
|
||||||
partial_verification_key
|
|
||||||
.beta_g2
|
|
||||||
.iter()
|
|
||||||
.skip(num_private_attributes),
|
|
||||||
) {
|
|
||||||
// (s^pub_j, beta_j)
|
|
||||||
terms.push((
|
|
||||||
(blind_sig.0 * pub_attr).to_affine(),
|
|
||||||
G2Prepared::from(beta_g2.to_affine()),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the references to all the terms to get the arguments the miller loop expects
|
|
||||||
let terms_refs = terms.iter().map(|(g1, g2)| (g1, g2)).collect::<Vec<_>>();
|
|
||||||
|
|
||||||
// since checking whether e(a, b) == e(c, d)
|
|
||||||
// is equivalent to checking e(a, b) • e(c, d)^{-1} == id
|
|
||||||
// and thus to e(a, b) • e(c^{-1}, d) == id
|
|
||||||
//
|
|
||||||
// compute e(c^1, g2) • e(s, alpha) • e(cm_0, beta_0) • e(cm_i, beta_i) • (s^pub_0, beta_{i+1}) (s^pub_j, beta_{i + j})
|
|
||||||
multi_miller_loop(&terms_refs)
|
|
||||||
.final_exponentiation()
|
|
||||||
.is_identity()
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub fn sign(
|
pub fn sign(
|
||||||
params: &mut Parameters,
|
params: &mut Parameters,
|
||||||
@@ -446,7 +354,6 @@ pub fn sign(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::scheme::keygen::keygen;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn blind_sign_request_bytes_roundtrip() {
|
fn blind_sign_request_bytes_roundtrip() {
|
||||||
@@ -478,81 +385,4 @@ mod tests {
|
|||||||
lambda
|
lambda
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn successful_verify_partial_blind_signature() {
|
|
||||||
let params = Parameters::new(4).unwrap();
|
|
||||||
let private_attributes = params.n_random_scalars(2);
|
|
||||||
let public_attributes = params.n_random_scalars(2);
|
|
||||||
|
|
||||||
let (_commitments_openings, request) =
|
|
||||||
prepare_blind_sign(¶ms, &private_attributes, &public_attributes).unwrap();
|
|
||||||
|
|
||||||
let validator_keypair = keygen(¶ms);
|
|
||||||
let blind_sig = blind_sign(
|
|
||||||
¶ms,
|
|
||||||
&validator_keypair.secret_key(),
|
|
||||||
&request,
|
|
||||||
&public_attributes,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert!(verify_partial_blind_signature(
|
|
||||||
¶ms,
|
|
||||||
&request,
|
|
||||||
&public_attributes,
|
|
||||||
&blind_sig,
|
|
||||||
&validator_keypair.verification_key()
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn successful_verify_partial_blind_signature_no_public_attributes() {
|
|
||||||
let params = Parameters::new(4).unwrap();
|
|
||||||
let private_attributes = params.n_random_scalars(2);
|
|
||||||
|
|
||||||
let (_commitments_openings, request) =
|
|
||||||
prepare_blind_sign(¶ms, &private_attributes, &[]).unwrap();
|
|
||||||
|
|
||||||
let validator_keypair = keygen(¶ms);
|
|
||||||
let blind_sig =
|
|
||||||
blind_sign(¶ms, &validator_keypair.secret_key(), &request, &[]).unwrap();
|
|
||||||
|
|
||||||
assert!(verify_partial_blind_signature(
|
|
||||||
¶ms,
|
|
||||||
&request,
|
|
||||||
&[],
|
|
||||||
&blind_sig,
|
|
||||||
&validator_keypair.verification_key()
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn fail_verify_partial_blind_signature_with_wrong_key() {
|
|
||||||
let params = Parameters::new(4).unwrap();
|
|
||||||
let private_attributes = params.n_random_scalars(2);
|
|
||||||
let public_attributes = params.n_random_scalars(2);
|
|
||||||
|
|
||||||
let (_commitments_openings, request) =
|
|
||||||
prepare_blind_sign(¶ms, &private_attributes, &public_attributes).unwrap();
|
|
||||||
|
|
||||||
let validator_keypair = keygen(¶ms);
|
|
||||||
let validator2_keypair = keygen(¶ms);
|
|
||||||
let blind_sig = blind_sign(
|
|
||||||
¶ms,
|
|
||||||
&validator_keypair.secret_key(),
|
|
||||||
&request,
|
|
||||||
&public_attributes,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// this assertion should fail, as we try to verify with a wrong validator key
|
|
||||||
assert!(!verify_partial_blind_signature(
|
|
||||||
¶ms,
|
|
||||||
&request,
|
|
||||||
&public_attributes,
|
|
||||||
&blind_sig,
|
|
||||||
&validator2_keypair.verification_key()
|
|
||||||
),);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -180,10 +180,10 @@ impl TunDevice {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// TODO: expire old entries
|
// TODO: expire old entries
|
||||||
// #[allow(irrefutable_let_patterns)]
|
#[allow(irrefutable_let_patterns)]
|
||||||
// if let RoutingMode::Nat(nat_table) = &mut self.routing_mode {
|
if let RoutingMode::Nat(nat_table) = &mut self.routing_mode {
|
||||||
// nat_table.nat_table.insert(src_addr, tag);
|
nat_table.nat_table.insert(src_addr, tag);
|
||||||
// }
|
}
|
||||||
|
|
||||||
timeout(
|
timeout(
|
||||||
Duration::from_millis(TUN_WRITE_TIMEOUT_MS),
|
Duration::from_millis(TUN_WRITE_TIMEOUT_MS),
|
||||||
@@ -196,13 +196,11 @@ impl TunDevice {
|
|||||||
|
|
||||||
// Receive reponse packets from the wild internet
|
// Receive reponse packets from the wild internet
|
||||||
async fn handle_tun_read(&self, packet: &[u8]) -> Result<(), TunDeviceError> {
|
async fn handle_tun_read(&self, packet: &[u8]) -> Result<(), TunDeviceError> {
|
||||||
// let ParsedAddresses { src_addr, dst_addr } = parse_src_dst_address(packet)?;
|
let ParsedAddresses { src_addr, dst_addr } = parse_src_dst_address(packet)?;
|
||||||
// log::debug!(
|
log::debug!(
|
||||||
// "iface: read Packet({dst_addr} <- {src_addr}, {} bytes)",
|
"iface: read Packet({src_addr} -> {dst_addr}, {} bytes)",
|
||||||
// packet.len(),
|
packet.len(),
|
||||||
// );
|
);
|
||||||
let dst_addr =
|
|
||||||
parse_dst_addr(packet).ok_or(TunDeviceError::UnableToParseAddressIpHeaderMissing)?;
|
|
||||||
|
|
||||||
// Route packet to the correct peer.
|
// Route packet to the correct peer.
|
||||||
|
|
||||||
@@ -222,14 +220,13 @@ impl TunDevice {
|
|||||||
|
|
||||||
// But we can also do it by consulting the NAT table.
|
// But we can also do it by consulting the NAT table.
|
||||||
RoutingMode::Nat(ref nat_table) => {
|
RoutingMode::Nat(ref nat_table) => {
|
||||||
// if let Some(tag) = nat_table.nat_table.get(&dst_addr) {
|
if let Some(tag) = nat_table.nat_table.get(&dst_addr) {
|
||||||
// log::debug!("Forward packet with NAT tag: {tag}");
|
log::debug!("Forward packet with NAT tag: {tag}");
|
||||||
return self
|
return self
|
||||||
.tun_task_response_tx
|
.tun_task_response_tx
|
||||||
// .try_send((*tag, packet.to_vec()))
|
.try_send((*tag, packet.to_vec()))
|
||||||
.try_send((0, packet.to_vec()))
|
.map_err(|err| err.into());
|
||||||
.map_err(|err| err.into());
|
}
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,37 +287,3 @@ fn parse_src_dst_address(packet: &[u8]) -> Result<ParsedAddresses, TunDeviceErro
|
|||||||
None => Err(TunDeviceError::UnableToParseAddressIpHeaderMissing),
|
None => Err(TunDeviceError::UnableToParseAddressIpHeaderMissing),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copyright (c) 2019 Cloudflare, Inc. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: BSD-3-Clause
|
|
||||||
const IPV4_MIN_HEADER_SIZE: usize = 20;
|
|
||||||
const IPV4_DST_IP_OFF: usize = 16;
|
|
||||||
const IPV4_IP_SZ: usize = 4;
|
|
||||||
|
|
||||||
const IPV6_MIN_HEADER_SIZE: usize = 40;
|
|
||||||
const IPV6_DST_IP_OFF: usize = 24;
|
|
||||||
const IPV6_IP_SZ: usize = 16;
|
|
||||||
|
|
||||||
pub fn parse_dst_addr(packet: &[u8]) -> Option<IpAddr> {
|
|
||||||
if packet.is_empty() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
match packet[0] >> 4 {
|
|
||||||
4 if packet.len() >= IPV4_MIN_HEADER_SIZE => {
|
|
||||||
let addr_bytes: [u8; IPV4_IP_SZ] = packet
|
|
||||||
[IPV4_DST_IP_OFF..IPV4_DST_IP_OFF + IPV4_IP_SZ]
|
|
||||||
.try_into()
|
|
||||||
.unwrap();
|
|
||||||
Some(IpAddr::from(addr_bytes))
|
|
||||||
}
|
|
||||||
6 if packet.len() >= IPV6_MIN_HEADER_SIZE => {
|
|
||||||
let addr_bytes: [u8; IPV6_IP_SZ] = packet
|
|
||||||
[IPV6_DST_IP_OFF..IPV6_DST_IP_OFF + IPV6_IP_SZ]
|
|
||||||
.try_into()
|
|
||||||
.unwrap();
|
|
||||||
Some(IpAddr::from(addr_bytes))
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "explorer-api"
|
name = "explorer-api"
|
||||||
version = "1.1.31"
|
version = "1.1.32"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nym-gateway"
|
name = "nym-gateway"
|
||||||
license = "GPL-3"
|
license = "GPL-3"
|
||||||
version = "1.1.31"
|
version = "1.1.32"
|
||||||
authors = [
|
authors = [
|
||||||
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
|
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
|
||||||
"Jędrzej Stuczyński <andrew@nymtech.net>",
|
"Jędrzej Stuczyński <andrew@nymtech.net>",
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nym-mixnode"
|
name = "nym-mixnode"
|
||||||
license = "GPL-3"
|
license = "GPL-3"
|
||||||
version = "1.1.33"
|
version = "1.1.34"
|
||||||
authors = [
|
authors = [
|
||||||
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
|
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
|
||||||
"Jędrzej Stuczyński <andrew@nymtech.net>",
|
"Jędrzej Stuczyński <andrew@nymtech.net>",
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nym-api"
|
name = "nym-api"
|
||||||
license = "GPL-3"
|
license = "GPL-3"
|
||||||
version = "1.1.33"
|
version = "1.1.34"
|
||||||
authors = [
|
authors = [
|
||||||
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
|
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
|
||||||
"Jędrzej Stuczyński <andrew@nymtech.net>",
|
"Jędrzej Stuczyński <andrew@nymtech.net>",
|
||||||
|
|||||||
@@ -168,7 +168,6 @@ impl MixnetClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct MixnetClientSender {
|
pub struct MixnetClientSender {
|
||||||
client_input: ClientInput,
|
client_input: ClientInput,
|
||||||
packet_type: Option<PacketType>,
|
packet_type: Option<PacketType>,
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ license.workspace = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
bincode = "1.3.3"
|
bincode = "1.3.3"
|
||||||
bytes = "1.5.0"
|
bytes = "1.5.0"
|
||||||
dashmap.workspace = true
|
|
||||||
etherparse = "0.13.0"
|
etherparse = "0.13.0"
|
||||||
futures = { workspace = true }
|
futures = { workspace = true }
|
||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
@@ -28,7 +27,6 @@ nym-task = { path = "../../common/task" }
|
|||||||
nym-tun = { path = "../../common/tun" }
|
nym-tun = { path = "../../common/tun" }
|
||||||
nym-wireguard = { path = "../../common/wireguard" }
|
nym-wireguard = { path = "../../common/wireguard" }
|
||||||
nym-wireguard-types = { path = "../../common/wireguard-types" }
|
nym-wireguard-types = { path = "../../common/wireguard-types" }
|
||||||
rand = "0.8.5"
|
|
||||||
reqwest.workspace = true
|
reqwest.workspace = true
|
||||||
serde = { workspace = true, features = ["derive"] }
|
serde = { workspace = true, features = ["derive"] }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
|
|||||||
@@ -30,9 +30,6 @@ pub enum IpPacketRouterError {
|
|||||||
#[error("the entity wrapping the network requester has disconnected")]
|
#[error("the entity wrapping the network requester has disconnected")]
|
||||||
DisconnectedParent,
|
DisconnectedParent,
|
||||||
|
|
||||||
#[error("received packet has an invalid version: {0}")]
|
|
||||||
InvalidPacketVersion(u8),
|
|
||||||
|
|
||||||
#[error("failed to deserialize tagged packet: {source}")]
|
#[error("failed to deserialize tagged packet: {source}")]
|
||||||
FailedToDeserializeTaggedPacket { source: bincode::Error },
|
FailedToDeserializeTaggedPacket { source: bincode::Error },
|
||||||
|
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
use std::{
|
|
||||||
collections::HashMap,
|
|
||||||
net::{IpAddr, Ipv4Addr},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{ConnectedClient, TUN_DEVICE_ADDRESS};
|
|
||||||
|
|
||||||
// Find an available IP address in self.connected_clients
|
|
||||||
// TODO: make this nicer
|
|
||||||
fn generate_random_ip_within_subnet() -> Ipv4Addr {
|
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
// Generate a random number in the range 1-254
|
|
||||||
let last_octet = rand::Rng::gen_range(&mut rng, 1..=254);
|
|
||||||
Ipv4Addr::new(10, 0, 0, last_octet)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_ip_taken(
|
|
||||||
connected_clients: &HashMap<IpAddr, ConnectedClient>,
|
|
||||||
tun_ip: Ipv4Addr,
|
|
||||||
ip: Ipv4Addr,
|
|
||||||
) -> bool {
|
|
||||||
connected_clients.contains_key(&ip.into()) || ip == tun_ip
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: brute force approach. We could consider using a more efficient algorithm
|
|
||||||
pub(crate) fn find_new_ip(connected_clients: &HashMap<IpAddr, ConnectedClient>) -> Option<IpAddr> {
|
|
||||||
let mut new_ip = generate_random_ip_within_subnet();
|
|
||||||
let mut tries = 0;
|
|
||||||
let tun_ip = TUN_DEVICE_ADDRESS.parse::<Ipv4Addr>().unwrap();
|
|
||||||
while is_ip_taken(connected_clients, tun_ip, new_ip) {
|
|
||||||
new_ip = generate_random_ip_within_subnet();
|
|
||||||
tries += 1;
|
|
||||||
if tries > 100 {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(new_ip.into())
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,8 @@
|
|||||||
#![cfg_attr(not(target_os = "linux"), allow(dead_code))]
|
#![cfg_attr(not(target_os = "linux"), allow(dead_code))]
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
|
||||||
net::{IpAddr, SocketAddr},
|
net::{IpAddr, SocketAddr},
|
||||||
path::Path,
|
path::Path,
|
||||||
sync::Arc,
|
|
||||||
time::Duration,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use error::IpPacketRouterError;
|
use error::IpPacketRouterError;
|
||||||
@@ -14,10 +11,6 @@ use nym_client_core::{
|
|||||||
client::mix_traffic::transceiver::GatewayTransceiver,
|
client::mix_traffic::transceiver::GatewayTransceiver,
|
||||||
config::disk_persistence::CommonClientPaths, HardcodedTopologyProvider, TopologyProvider,
|
config::disk_persistence::CommonClientPaths, HardcodedTopologyProvider, TopologyProvider,
|
||||||
};
|
};
|
||||||
use nym_ip_packet_requests::{
|
|
||||||
DynamicConnectFailureReason, IpPacketRequest, IpPacketRequestData, IpPacketResponse,
|
|
||||||
StaticConnectFailureReason,
|
|
||||||
};
|
|
||||||
use nym_sdk::{
|
use nym_sdk::{
|
||||||
mixnet::{InputMessage, MixnetMessageSender, Recipient},
|
mixnet::{InputMessage, MixnetMessageSender, Recipient},
|
||||||
NymNetworkDetails,
|
NymNetworkDetails,
|
||||||
@@ -32,7 +25,6 @@ pub use crate::config::Config;
|
|||||||
|
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
mod generate_new_ip;
|
|
||||||
mod request_filter;
|
mod request_filter;
|
||||||
|
|
||||||
// The interface used to route traffic
|
// The interface used to route traffic
|
||||||
@@ -40,9 +32,6 @@ pub const TUN_BASE_NAME: &str = "nymtun";
|
|||||||
pub const TUN_DEVICE_ADDRESS: &str = "10.0.0.1";
|
pub const TUN_DEVICE_ADDRESS: &str = "10.0.0.1";
|
||||||
pub const TUN_DEVICE_NETMASK: &str = "255.255.255.0";
|
pub const TUN_DEVICE_NETMASK: &str = "255.255.255.0";
|
||||||
|
|
||||||
const DISCONNECT_TIMER_INTERVAL: Duration = Duration::from_secs(10);
|
|
||||||
const CLIENT_INACTIVITY_TIMEOUT: Duration = Duration::from_secs(5 * 60);
|
|
||||||
|
|
||||||
pub struct OnStartData {
|
pub struct OnStartData {
|
||||||
// to add more fields as required
|
// to add more fields as required
|
||||||
pub address: Recipient,
|
pub address: Recipient,
|
||||||
@@ -168,10 +157,9 @@ impl IpPacketRouterBuilder {
|
|||||||
_config: self.config,
|
_config: self.config,
|
||||||
request_filter: request_filter.clone(),
|
request_filter: request_filter.clone(),
|
||||||
tun_task_tx,
|
tun_task_tx,
|
||||||
tun_task_response_rx: Some(tun_task_response_rx),
|
tun_task_response_rx,
|
||||||
mixnet_client,
|
mixnet_client,
|
||||||
task_handle,
|
task_handle,
|
||||||
connected_clients: Default::default(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
log::info!("The address of this client is: {self_address}");
|
log::info!("The address of this client is: {self_address}");
|
||||||
@@ -191,173 +179,85 @@ impl IpPacketRouterBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(not(target_os = "linux"), allow(unused))]
|
#[allow(unused)]
|
||||||
struct IpPacketRouter {
|
struct IpPacketRouter {
|
||||||
_config: Config,
|
_config: Config,
|
||||||
request_filter: request_filter::RequestFilter,
|
request_filter: request_filter::RequestFilter,
|
||||||
tun_task_tx: nym_tun::tun_task_channel::TunTaskTx,
|
tun_task_tx: nym_tun::tun_task_channel::TunTaskTx,
|
||||||
tun_task_response_rx: Option<nym_tun::tun_task_channel::TunTaskResponseRx>,
|
tun_task_response_rx: nym_tun::tun_task_channel::TunTaskResponseRx,
|
||||||
mixnet_client: nym_sdk::mixnet::MixnetClient,
|
mixnet_client: nym_sdk::mixnet::MixnetClient,
|
||||||
task_handle: TaskHandle,
|
task_handle: TaskHandle,
|
||||||
connected_clients: HashMap<IpAddr, ConnectedClient>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ConnectedClient {
|
#[allow(unused)]
|
||||||
nym_address: Recipient,
|
|
||||||
last_activity: std::time::Instant,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(not(target_os = "linux"), allow(unused))]
|
|
||||||
impl IpPacketRouter {
|
impl IpPacketRouter {
|
||||||
async fn on_static_connect_request(
|
async fn run(mut self) -> Result<(), IpPacketRouterError> {
|
||||||
&mut self,
|
let mut task_client = self.task_handle.fork("main_loop");
|
||||||
connect_request: nym_ip_packet_requests::StaticConnectRequest,
|
|
||||||
connected_client_tx: &tokio::sync::mpsc::Sender<ConnectedClientEvent>,
|
|
||||||
) -> Result<Option<IpPacketResponse>, IpPacketRouterError> {
|
|
||||||
log::info!(
|
|
||||||
"Received static connect request from {sender_address}",
|
|
||||||
sender_address = connect_request.reply_to
|
|
||||||
);
|
|
||||||
|
|
||||||
let request_id = connect_request.request_id;
|
while !task_client.is_shutdown() {
|
||||||
let requested_ip = connect_request.ip;
|
tokio::select! {
|
||||||
let reply_to = connect_request.reply_to;
|
_ = task_client.recv() => {
|
||||||
// TODO: ignoring reply_to_hops and reply_to_avg_mix_delays for now
|
log::debug!("IpPacketRouter [main loop]: received shutdown");
|
||||||
|
},
|
||||||
|
msg = self.mixnet_client.next() => {
|
||||||
|
if let Some(msg) = msg {
|
||||||
|
if let Err(err) = self.on_message(msg).await {
|
||||||
|
log::error!("Error handling mixnet message: {err}");
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
log::trace!("IpPacketRouter [main loop]: stopping since channel closed");
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
packet = self.tun_task_response_rx.recv() => {
|
||||||
|
if let Some((_tag, packet)) = packet {
|
||||||
|
// Read recipient from env variable NYM_CLIENT_ADDR which is a base58
|
||||||
|
// string of the nym-address of the client that the packet should be
|
||||||
|
// sent back to.
|
||||||
|
//
|
||||||
|
// In the near future we will let the client expose it's nym-address
|
||||||
|
// directly, and after that, provide SURBS
|
||||||
|
let recipient = std::env::var("NYM_CLIENT_ADDR").ok().and_then(|addr| {
|
||||||
|
Recipient::try_from_base58_string(addr).ok()
|
||||||
|
});
|
||||||
|
|
||||||
// Check that the IP is available in the set of connected clients
|
if let Some(recipient) = recipient {
|
||||||
let is_ip_taken = self.connected_clients.contains_key(&requested_ip);
|
let lane = TransmissionLane::General;
|
||||||
// let is_ip_taken = connected_clients
|
let packet_type = None;
|
||||||
// .lock()
|
let input_message = InputMessage::new_regular(recipient, packet, lane, packet_type);
|
||||||
// .unwrap()
|
|
||||||
// .contains_key(&requested_ip);
|
|
||||||
|
|
||||||
// Check that the nym address isn't already registered
|
if let Err(err) = self.mixnet_client.send(input_message).await {
|
||||||
let is_nym_address_taken = self
|
log::error!("IpPacketRouter [main loop]: failed to send packet to mixnet: {err}");
|
||||||
.connected_clients
|
};
|
||||||
// .lock()
|
} else {
|
||||||
// .unwrap()
|
log::error!("NYM_CLIENT_ADDR not set or invalid");
|
||||||
.values()
|
}
|
||||||
.any(|client| client.nym_address == reply_to);
|
} else {
|
||||||
|
log::trace!("IpPacketRouter [main loop]: stopping since channel closed");
|
||||||
match (is_ip_taken, is_nym_address_taken) {
|
break;
|
||||||
(true, true) => {
|
}
|
||||||
log::info!("Connecting an already connected client");
|
|
||||||
// Update the last activity time for the client
|
|
||||||
if let Some(client) = self.connected_clients.get_mut(&requested_ip) {
|
|
||||||
client.last_activity = std::time::Instant::now();
|
|
||||||
} else {
|
|
||||||
log::error!("Failed to update last activity time for client");
|
|
||||||
}
|
}
|
||||||
Ok(Some(IpPacketResponse::new_static_connect_success(
|
|
||||||
request_id, reply_to,
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
(false, false) => {
|
|
||||||
log::info!("Connecting a new client");
|
|
||||||
self.connected_clients.insert(
|
|
||||||
requested_ip,
|
|
||||||
ConnectedClient {
|
|
||||||
nym_address: reply_to,
|
|
||||||
last_activity: std::time::Instant::now(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
connected_client_tx
|
|
||||||
.send(ConnectedClientEvent::Connect(requested_ip, reply_to))
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
Ok(Some(IpPacketResponse::new_static_connect_success(
|
|
||||||
request_id, reply_to,
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
(true, false) => {
|
|
||||||
log::info!("Requested IP is not available");
|
|
||||||
Ok(Some(IpPacketResponse::new_static_connect_failure(
|
|
||||||
request_id,
|
|
||||||
reply_to,
|
|
||||||
StaticConnectFailureReason::RequestedIpAlreadyInUse,
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
(false, true) => {
|
|
||||||
log::info!("Nym address is already registered");
|
|
||||||
Ok(Some(IpPacketResponse::new_static_connect_failure(
|
|
||||||
request_id,
|
|
||||||
reply_to,
|
|
||||||
StaticConnectFailureReason::RequestedNymAddressAlreadyInUse,
|
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
log::info!("IpPacketRouter: stopping");
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn on_dynamic_connect_request(
|
async fn on_message(
|
||||||
&mut self,
|
&mut self,
|
||||||
connect_request: nym_ip_packet_requests::DynamicConnectRequest,
|
reconstructed: ReconstructedMessage,
|
||||||
connected_client_tx: &tokio::sync::mpsc::Sender<ConnectedClientEvent>,
|
) -> Result<(), IpPacketRouterError> {
|
||||||
) -> Result<Option<IpPacketResponse>, IpPacketRouterError> {
|
log::debug!(
|
||||||
log::info!(
|
"Received message with sender_tag: {:?}",
|
||||||
"Received dynamic connect request from {sender_address}",
|
reconstructed.sender_tag
|
||||||
sender_address = connect_request.reply_to
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let request_id = connect_request.request_id;
|
let tagged_packet =
|
||||||
let reply_to = connect_request.reply_to;
|
nym_ip_packet_requests::TaggedIpPacket::from_reconstructed_message(&reconstructed)
|
||||||
// TODO: ignoring reply_to_hops and reply_to_avg_mix_delays for now
|
.map_err(|err| IpPacketRouterError::FailedToDeserializeTaggedPacket {
|
||||||
|
source: err,
|
||||||
// Check if it's the same client connecting again, then we just reuse the same IP
|
})?;
|
||||||
// TODO: this is problematic. Until we sign connect requests this means you can spam people
|
|
||||||
// with return traffic
|
|
||||||
let existing_ip = self.connected_clients.iter().find_map(|(ip, client)| {
|
|
||||||
if client.nym_address == reply_to {
|
|
||||||
Some(*ip)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Some(existing_ip) = existing_ip {
|
|
||||||
log::info!("Found existing client for nym address");
|
|
||||||
// Update the last activity time for the client
|
|
||||||
if let Some(client) = self.connected_clients.get_mut(&existing_ip) {
|
|
||||||
client.last_activity = std::time::Instant::now();
|
|
||||||
} else {
|
|
||||||
log::error!("Failed to update last activity time for client");
|
|
||||||
}
|
|
||||||
return Ok(Some(IpPacketResponse::new_dynamic_connect_success(
|
|
||||||
request_id,
|
|
||||||
reply_to,
|
|
||||||
existing_ip,
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
let Some(new_ip) = generate_new_ip::find_new_ip(&self.connected_clients) else {
|
|
||||||
log::info!("No available IP address");
|
|
||||||
return Ok(Some(IpPacketResponse::new_dynamic_connect_failure(
|
|
||||||
request_id,
|
|
||||||
reply_to,
|
|
||||||
DynamicConnectFailureReason::NoAvailableIp,
|
|
||||||
)));
|
|
||||||
};
|
|
||||||
|
|
||||||
self.connected_clients.insert(
|
|
||||||
new_ip,
|
|
||||||
ConnectedClient {
|
|
||||||
nym_address: reply_to,
|
|
||||||
last_activity: std::time::Instant::now(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
connected_client_tx
|
|
||||||
.send(ConnectedClientEvent::Connect(new_ip, reply_to))
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
Ok(Some(IpPacketResponse::new_dynamic_connect_success(
|
|
||||||
request_id, reply_to, new_ip,
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn on_data_request(
|
|
||||||
&mut self,
|
|
||||||
data_request: nym_ip_packet_requests::DataRequest,
|
|
||||||
) -> Result<Option<IpPacketResponse>, IpPacketRouterError> {
|
|
||||||
log::info!("Received data request");
|
|
||||||
|
|
||||||
// We don't forward packets that we are not able to parse. BUT, there might be a good
|
// We don't forward packets that we are not able to parse. BUT, there might be a good
|
||||||
// reason to still forward them.
|
// reason to still forward them.
|
||||||
@@ -371,20 +271,11 @@ impl IpPacketRouter {
|
|||||||
src_addr,
|
src_addr,
|
||||||
dst_addr,
|
dst_addr,
|
||||||
dst,
|
dst,
|
||||||
} = parse_packet(&data_request.ip_packet)?;
|
} = parse_packet(&tagged_packet.packet)?;
|
||||||
|
|
||||||
let dst_str = dst.map_or(dst_addr.to_string(), |dst| dst.to_string());
|
let dst_str = dst.map_or(dst_addr.to_string(), |dst| dst.to_string());
|
||||||
log::info!("Received packet: {packet_type}: {src_addr} -> {dst_str}");
|
log::info!("Received packet: {packet_type}: {src_addr} -> {dst_str}");
|
||||||
|
|
||||||
// Check if there is a connected client for this src_addr. If there is, update the last activity time
|
|
||||||
// for the client. If there isn't, drop the packet.
|
|
||||||
if let Some(client) = self.connected_clients.get_mut(&src_addr) {
|
|
||||||
client.last_activity = std::time::Instant::now();
|
|
||||||
} else {
|
|
||||||
log::info!("Dropping packet: no connected client for {src_addr}");
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filter check
|
// Filter check
|
||||||
if let Some(dst) = dst {
|
if let Some(dst) = dst {
|
||||||
if !self.request_filter.check_address(&dst).await {
|
if !self.request_filter.check_address(&dst).await {
|
||||||
@@ -397,200 +288,16 @@ impl IpPacketRouter {
|
|||||||
log::warn!("Ignoring filter check for packet without port number! TODO!");
|
log::warn!("Ignoring filter check for packet without port number! TODO!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: consider changing from Vec<u8> to bytes::Bytes?
|
// TODO: set the tag correctly. Can we just reuse sender_tag?
|
||||||
// TODO: consider just removing the tag
|
let peer_tag = 0;
|
||||||
let tag = 0;
|
|
||||||
self.tun_task_tx
|
self.tun_task_tx
|
||||||
.try_send((tag, data_request.ip_packet.into()))
|
.try_send((peer_tag, tagged_packet.packet.into()))
|
||||||
.map_err(|err| IpPacketRouterError::FailedToSendPacketToTun { source: err })?;
|
.map_err(|err| IpPacketRouterError::FailedToSendPacketToTun { source: err })?;
|
||||||
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
async fn on_reconstructed_message(
|
|
||||||
&mut self,
|
|
||||||
reconstructed: ReconstructedMessage,
|
|
||||||
connected_client_tx: &tokio::sync::mpsc::Sender<ConnectedClientEvent>,
|
|
||||||
) -> Result<Option<IpPacketResponse>, IpPacketRouterError> {
|
|
||||||
log::debug!(
|
|
||||||
"Received message with sender_tag: {:?}",
|
|
||||||
reconstructed.sender_tag
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check version of request
|
|
||||||
if let Some(version) = reconstructed.message.first() {
|
|
||||||
// The idea is that in the future we can add logic here to parse older versions to stay
|
|
||||||
// backwards compatible.
|
|
||||||
if *version != nym_ip_packet_requests::CURRENT_VERSION {
|
|
||||||
log::warn!("Received packet with invalid version");
|
|
||||||
return Err(IpPacketRouterError::InvalidPacketVersion(*version));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let request = IpPacketRequest::from_reconstructed_message(&reconstructed)
|
|
||||||
.map_err(|err| IpPacketRouterError::FailedToDeserializeTaggedPacket { source: err })?;
|
|
||||||
|
|
||||||
match request.data {
|
|
||||||
IpPacketRequestData::StaticConnect(connect_request) => {
|
|
||||||
self.on_static_connect_request(connect_request, connected_client_tx)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
IpPacketRequestData::DynamicConnect(connect_request) => {
|
|
||||||
self.on_dynamic_connect_request(connect_request, connected_client_tx)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
IpPacketRequestData::Data(data_request) => self.on_data_request(data_request).await,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn run(mut self) -> Result<(), IpPacketRouterError> {
|
|
||||||
let mut task_client = self.task_handle.fork("main_loop");
|
|
||||||
let mut disconnect_timer = tokio::time::interval(DISCONNECT_TIMER_INTERVAL);
|
|
||||||
|
|
||||||
let mixnet_client_sender = self.mixnet_client.split_sender();
|
|
||||||
let mixnet_client_sender_clone = mixnet_client_sender.clone();
|
|
||||||
|
|
||||||
// let connected_clients = Arc::new(std::sync::Mutex::new(
|
|
||||||
// HashMap::<IpAddr, ConnectedClient>::new(),
|
|
||||||
// ));
|
|
||||||
// let connected_clients_clone = connected_clients.clone();
|
|
||||||
|
|
||||||
let tun_task_response_rx = self.tun_task_response_rx.take();
|
|
||||||
|
|
||||||
let (connected_client_tx, mut connected_client_rx) = tokio::sync::mpsc::channel(16);
|
|
||||||
|
|
||||||
// Spawn TUN listener
|
|
||||||
tokio::spawn(async move {
|
|
||||||
let mut connected_clients = HashMap::<IpAddr, ConnectedClient>::new();
|
|
||||||
let mut tun_task_response_rx = tun_task_response_rx.unwrap();
|
|
||||||
loop {
|
|
||||||
tokio::select! {
|
|
||||||
connected_client_event = connected_client_rx.recv() => {
|
|
||||||
match connected_client_event {
|
|
||||||
Some(ConnectedClientEvent::Connect(ip, nym_addr)) => {
|
|
||||||
log::trace!("Connect client: {ip}");
|
|
||||||
connected_clients.insert(ip, ConnectedClient {
|
|
||||||
nym_address: nym_addr,
|
|
||||||
last_activity: std::time::Instant::now(),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
Some(ConnectedClientEvent::Disconnect(ip)) => {
|
|
||||||
log::trace!("Disconnect client: {ip}");
|
|
||||||
connected_clients.remove(&ip);
|
|
||||||
},
|
|
||||||
None => {},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
packet = tun_task_response_rx.recv() => {
|
|
||||||
if let Some((_tag, packet)) = packet {
|
|
||||||
// TODO: skip full parsing since we only need dst_addr
|
|
||||||
// let Ok(ParsedPacket {
|
|
||||||
// packet_type: _,
|
|
||||||
// src_addr: _,
|
|
||||||
// dst_addr,
|
|
||||||
// dst: _,
|
|
||||||
// }) = parse_packet(&packet) else {
|
|
||||||
// log::warn!("Failed to parse packet");
|
|
||||||
// continue;
|
|
||||||
// };
|
|
||||||
let Some(dst_addr) = parse_dst_addr(&packet) else {
|
|
||||||
log::warn!("Failed to parse packet");
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
let recipient = connected_clients.get(&dst_addr).map(|c| c.nym_address);
|
|
||||||
|
|
||||||
if let Some(recipient) = recipient {
|
|
||||||
let lane = TransmissionLane::General;
|
|
||||||
let packet_type = None;
|
|
||||||
let response_packet = IpPacketResponse::new_ip_packet(packet.into()).to_bytes();
|
|
||||||
let Ok(response_packet) = response_packet else {
|
|
||||||
log::error!("Failed to serialize response packet");
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
let input_message = InputMessage::new_regular(recipient, response_packet, lane, packet_type);
|
|
||||||
|
|
||||||
if let Err(err) = mixnet_client_sender_clone.send(input_message).await {
|
|
||||||
log::error!("IpPacketRouter [main loop]: failed to send packet to mixnet: {err}");
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
log::error!("IpPacketRouter [main loop]: no nym-address recipient for packet");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log::trace!("IpPacketRouter [main loop]: stopping since channel closed");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
while !task_client.is_shutdown() {
|
|
||||||
tokio::select! {
|
|
||||||
_ = task_client.recv() => {
|
|
||||||
log::debug!("IpPacketRouter [main loop]: received shutdown");
|
|
||||||
},
|
|
||||||
_ = disconnect_timer.tick() => {
|
|
||||||
let now = std::time::Instant::now();
|
|
||||||
let inactive_clients: Vec<IpAddr> = self.connected_clients.iter()
|
|
||||||
.filter_map(|(ip, client)| {
|
|
||||||
if now.duration_since(client.last_activity) > CLIENT_INACTIVITY_TIMEOUT {
|
|
||||||
Some(*ip)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
for ip in inactive_clients {
|
|
||||||
log::info!("Disconnect inactive client: {ip}");
|
|
||||||
self.connected_clients.remove(&ip);
|
|
||||||
connected_client_tx.send(ConnectedClientEvent::Disconnect(ip)).await.unwrap();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
msg = self.mixnet_client.next() => {
|
|
||||||
if let Some(msg) = msg {
|
|
||||||
match self.on_reconstructed_message(msg, &connected_client_tx).await {
|
|
||||||
Ok(Some(response)) => {
|
|
||||||
let Some(recipient) = response.recipient() else {
|
|
||||||
log::error!("IpPacketRouter [main loop]: failed to get recipient from response");
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
let response_packet = response.to_bytes();
|
|
||||||
let Ok(response_packet) = response_packet else {
|
|
||||||
log::error!("Failed to serialize response packet");
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
let lane = TransmissionLane::General;
|
|
||||||
let packet_type = None;
|
|
||||||
let input_message = InputMessage::new_regular(*recipient, response_packet, lane, packet_type);
|
|
||||||
if let Err(err) = mixnet_client_sender.send(input_message).await {
|
|
||||||
log::error!("IpPacketRouter [main loop]: failed to send packet to mixnet: {err}");
|
|
||||||
};
|
|
||||||
},
|
|
||||||
Ok(None) => {
|
|
||||||
continue;
|
|
||||||
},
|
|
||||||
Err(err) => {
|
|
||||||
log::error!("Error handling mixnet message: {err}");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
log::trace!("IpPacketRouter [main loop]: stopping since channel closed");
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log::info!("IpPacketRouter: stopping");
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ConnectedClientEvent {
|
|
||||||
Disconnect(IpAddr),
|
|
||||||
Connect(IpAddr, Recipient),
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ParsedPacket<'a> {
|
struct ParsedPacket<'a> {
|
||||||
packet_type: &'a str,
|
packet_type: &'a str,
|
||||||
src_addr: IpAddr,
|
src_addr: IpAddr,
|
||||||
@@ -605,8 +312,8 @@ fn parse_packet(packet: &[u8]) -> Result<ParsedPacket, IpPacketRouterError> {
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
let (packet_type, dst_port) = match headers.transport {
|
let (packet_type, dst_port) = match headers.transport {
|
||||||
Some(etherparse::TransportSlice::Udp(header)) => ("udp", Some(header.destination_port())),
|
Some(etherparse::TransportSlice::Udp(header)) => ("ipv4", Some(header.destination_port())),
|
||||||
Some(etherparse::TransportSlice::Tcp(header)) => ("tcp", Some(header.destination_port())),
|
Some(etherparse::TransportSlice::Tcp(header)) => ("ipv6", Some(header.destination_port())),
|
||||||
Some(etherparse::TransportSlice::Icmpv4(_)) => ("icmpv4", None),
|
Some(etherparse::TransportSlice::Icmpv4(_)) => ("icmpv4", None),
|
||||||
Some(etherparse::TransportSlice::Icmpv6(_)) => ("icmpv6", None),
|
Some(etherparse::TransportSlice::Icmpv6(_)) => ("icmpv6", None),
|
||||||
Some(etherparse::TransportSlice::Unknown(_)) => ("unknown", None),
|
Some(etherparse::TransportSlice::Unknown(_)) => ("unknown", None),
|
||||||
@@ -686,37 +393,3 @@ async fn create_mixnet_client(
|
|||||||
.await
|
.await
|
||||||
.map_err(|err| IpPacketRouterError::FailedToConnectToMixnet { source: err })
|
.map_err(|err| IpPacketRouterError::FailedToConnectToMixnet { source: err })
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copyright (c) 2019 Cloudflare, Inc. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: BSD-3-Clause
|
|
||||||
const IPV4_MIN_HEADER_SIZE: usize = 20;
|
|
||||||
const IPV4_DST_IP_OFF: usize = 16;
|
|
||||||
const IPV4_IP_SZ: usize = 4;
|
|
||||||
|
|
||||||
const IPV6_MIN_HEADER_SIZE: usize = 40;
|
|
||||||
const IPV6_DST_IP_OFF: usize = 24;
|
|
||||||
const IPV6_IP_SZ: usize = 16;
|
|
||||||
|
|
||||||
pub fn parse_dst_addr(packet: &[u8]) -> Option<IpAddr> {
|
|
||||||
if packet.is_empty() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
match packet[0] >> 4 {
|
|
||||||
4 if packet.len() >= IPV4_MIN_HEADER_SIZE => {
|
|
||||||
let addr_bytes: [u8; IPV4_IP_SZ] = packet
|
|
||||||
[IPV4_DST_IP_OFF..IPV4_DST_IP_OFF + IPV4_IP_SZ]
|
|
||||||
.try_into()
|
|
||||||
.unwrap();
|
|
||||||
Some(IpAddr::from(addr_bytes))
|
|
||||||
}
|
|
||||||
6 if packet.len() >= IPV6_MIN_HEADER_SIZE => {
|
|
||||||
let addr_bytes: [u8; IPV6_IP_SZ] = packet
|
|
||||||
[IPV6_DST_IP_OFF..IPV6_DST_IP_OFF + IPV6_IP_SZ]
|
|
||||||
.try_into()
|
|
||||||
.unwrap();
|
|
||||||
Some(IpAddr::from(addr_bytes))
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nym-network-requester"
|
name = "nym-network-requester"
|
||||||
license = "GPL-3"
|
license = "GPL-3"
|
||||||
version = "1.1.31"
|
version = "1.1.32"
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
rust-version = "1.65"
|
rust-version = "1.65"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nym-network-statistics"
|
name = "nym-network-statistics"
|
||||||
version = "1.1.31"
|
version = "1.1.32"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nym-cli"
|
name = "nym-cli"
|
||||||
version = "1.1.32"
|
version = "1.1.33"
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user