Compare commits
46 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 02655d247d | |||
| dd9f4f24f1 | |||
| f6c2cab531 | |||
| f4dd9a915d | |||
| dcfd46ecf0 | |||
| d331e75375 | |||
| bac0f24cf7 | |||
| 6bba371c90 | |||
| 404b043591 | |||
| e09b33baff | |||
| 82bfab48a5 | |||
| e8956603d7 | |||
| a81e7e6c53 | |||
| 723e30fb1d | |||
| 951f8e7a74 | |||
| 4462dae45c | |||
| 8bfe670c9d | |||
| 7ca801fff3 | |||
| 8a92cca448 | |||
| 4308f602ea | |||
| 9ea2eafb2c | |||
| 061aa6b7bd | |||
| 3ee1e541ff | |||
| 866309cedf | |||
| 2d57ed49e8 | |||
| a08cc64fc7 | |||
| 23892fec8c | |||
| d807f66944 | |||
| 0861304368 | |||
| 077ea25990 | |||
| 77679064de | |||
| 2052577174 | |||
| 24a859d03c | |||
| b898ad3e97 | |||
| af3a216f71 | |||
| 7866cb0ae8 | |||
| 40adedb5e1 | |||
| c1660c2b27 | |||
| 26a8dec707 | |||
| 74481003e6 | |||
| 6d6eb186c0 | |||
| 6a4f8d502d | |||
| 84b497ab20 | |||
| 14d5e112d0 | |||
| 620c5e1188 | |||
| 60c740f723 |
@@ -0,0 +1,21 @@
|
||||
name: ci-cargo-deny
|
||||
on: [workflow_dispatch]
|
||||
jobs:
|
||||
cargo-deny:
|
||||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
matrix:
|
||||
checks:
|
||||
# - advisories
|
||||
- licenses
|
||||
- bans sources
|
||||
|
||||
continue-on-error: ${{ matrix.checks == 'licenses' }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: EmbarkStudios/cargo-deny-action@v1
|
||||
with:
|
||||
log-level: warn
|
||||
command: check ${{ matrix.checks }}
|
||||
argument: --all-features
|
||||
@@ -9,6 +9,7 @@
|
||||
target
|
||||
.env
|
||||
.env.dev
|
||||
envs/devnet.env
|
||||
/.vscode/settings.json
|
||||
validator/.vscode
|
||||
sample-configs/validator-config.toml
|
||||
|
||||
Generated
+37
-87
@@ -987,27 +987,13 @@ checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae"
|
||||
|
||||
[[package]]
|
||||
name = "bls12_381"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54757888b09a69be70b5ec303e382a74227392086ba808cb01eeca29233a2397"
|
||||
version = "0.8.0"
|
||||
source = "git+https://github.com/jstuczyn/bls12_381?branch=feature/gt-serialization-0.8.0#c4543fde7d02efea6ecfcf22e14476ddb516b483"
|
||||
dependencies = [
|
||||
"digest 0.9.0",
|
||||
"ff 0.10.1",
|
||||
"group 0.10.0",
|
||||
"pairing 0.20.0",
|
||||
"rand_core 0.6.4",
|
||||
"subtle 2.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bls12_381"
|
||||
version = "0.6.0"
|
||||
source = "git+https://github.com/jstuczyn/bls12_381?branch=gt-serialisation#10fb6f700bfda17c8475af3bfd31e3fec15f2278"
|
||||
dependencies = [
|
||||
"digest 0.9.0",
|
||||
"ff 0.11.1",
|
||||
"group 0.11.0",
|
||||
"pairing 0.21.0",
|
||||
"ff 0.13.0",
|
||||
"group 0.13.0",
|
||||
"pairing",
|
||||
"rand_core 0.6.4",
|
||||
"subtle 2.4.1",
|
||||
"zeroize",
|
||||
@@ -3030,26 +3016,6 @@ version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
|
||||
|
||||
[[package]]
|
||||
name = "ff"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0f40b2dcd8bc322217a5f6559ae5f9e9d1de202a2ecee2e9eafcbece7562a4f"
|
||||
dependencies = [
|
||||
"rand_core 0.6.4",
|
||||
"subtle 2.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ff"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "131655483be284720a17d74ff97592b8e76576dc25563148601df2d7c9080924"
|
||||
dependencies = [
|
||||
"rand_core 0.6.4",
|
||||
"subtle 2.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ff"
|
||||
version = "0.12.1"
|
||||
@@ -3066,6 +3032,7 @@ version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449"
|
||||
dependencies = [
|
||||
"bitvec",
|
||||
"rand_core 0.6.4",
|
||||
"subtle 2.4.1",
|
||||
]
|
||||
@@ -3519,30 +3486,6 @@ dependencies = [
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "group"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c363a5301b8f153d80747126a04b3c82073b9fe3130571a9d170cacdeaf7912"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"ff 0.10.1",
|
||||
"rand_core 0.6.4",
|
||||
"subtle 2.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "group"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"ff 0.11.1",
|
||||
"rand_core 0.6.4",
|
||||
"subtle 2.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "group"
|
||||
version = "0.12.1"
|
||||
@@ -4286,6 +4229,15 @@ dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.9"
|
||||
@@ -5937,6 +5889,7 @@ dependencies = [
|
||||
"futures-util",
|
||||
"getset",
|
||||
"humantime-serde",
|
||||
"itertools 0.12.0",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"nym-api-requests",
|
||||
@@ -6001,10 +5954,12 @@ dependencies = [
|
||||
"cosmwasm-std",
|
||||
"getset",
|
||||
"nym-coconut-interface",
|
||||
"nym-crypto",
|
||||
"nym-mixnet-contract-common",
|
||||
"nym-node-requests",
|
||||
"schemars",
|
||||
"serde",
|
||||
"tendermint",
|
||||
"ts-rs",
|
||||
]
|
||||
|
||||
@@ -6022,6 +5977,7 @@ dependencies = [
|
||||
"rand 0.7.3",
|
||||
"thiserror",
|
||||
"url",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6257,14 +6213,14 @@ dependencies = [
|
||||
name = "nym-coconut"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"bls12_381 0.6.0",
|
||||
"bls12_381",
|
||||
"bs58 0.4.0",
|
||||
"criterion",
|
||||
"digest 0.9.0",
|
||||
"doc-comment",
|
||||
"ff 0.11.1",
|
||||
"ff 0.13.0",
|
||||
"getrandom 0.2.10",
|
||||
"group 0.11.0",
|
||||
"group 0.13.0",
|
||||
"itertools 0.10.5",
|
||||
"nym-dkg",
|
||||
"nym-pemstore",
|
||||
@@ -6274,6 +6230,7 @@ dependencies = [
|
||||
"serde_derive",
|
||||
"sha2 0.9.9",
|
||||
"thiserror",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6364,7 +6321,7 @@ dependencies = [
|
||||
name = "nym-credentials"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bls12_381 0.5.0",
|
||||
"bls12_381",
|
||||
"cosmrs",
|
||||
"log",
|
||||
"nym-api-requests",
|
||||
@@ -6373,6 +6330,7 @@ dependencies = [
|
||||
"nym-validator-client",
|
||||
"rand 0.7.3",
|
||||
"thiserror",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6406,11 +6364,11 @@ name = "nym-dkg"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitvec",
|
||||
"bls12_381 0.6.0",
|
||||
"bls12_381",
|
||||
"bs58 0.4.0",
|
||||
"criterion",
|
||||
"ff 0.11.1",
|
||||
"group 0.11.0",
|
||||
"ff 0.13.0",
|
||||
"group 0.13.0",
|
||||
"lazy_static",
|
||||
"nym-contracts-common",
|
||||
"nym-pemstore",
|
||||
@@ -7572,6 +7530,7 @@ dependencies = [
|
||||
"nym-network-defaults",
|
||||
"nym-task",
|
||||
"nym-wireguard-types",
|
||||
"serde",
|
||||
"tokio",
|
||||
"x25519-dalek 2.0.0",
|
||||
]
|
||||
@@ -7882,20 +7841,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pairing"
|
||||
version = "0.20.0"
|
||||
version = "0.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7de9d09263c9966e8196fe0380c9dbbc7ea114b5cf371ba29004bc1f9c6db7f3"
|
||||
checksum = "81fec4625e73cf41ef4bb6846cafa6d44736525f442ba45e407c4a000a13996f"
|
||||
dependencies = [
|
||||
"group 0.10.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pairing"
|
||||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2e415e349a3006dd7d9482cdab1c980a845bed1377777d768cb693a44540b42"
|
||||
dependencies = [
|
||||
"group 0.11.0",
|
||||
"group 0.13.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -9790,9 +9740,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.107"
|
||||
version = "1.0.108"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65"
|
||||
checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
@@ -11014,16 +10964,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.9"
|
||||
version = "0.7.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d"
|
||||
checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-util",
|
||||
"hashbrown 0.12.3",
|
||||
"hashbrown 0.14.1",
|
||||
"pin-project-lite 0.2.13",
|
||||
"slab",
|
||||
"tokio",
|
||||
|
||||
+11
-1
@@ -162,7 +162,8 @@ serde_json = "1.0.91"
|
||||
tap = "1.0.1"
|
||||
time = "0.3.30"
|
||||
thiserror = "1.0.48"
|
||||
tokio = "1.24.1"
|
||||
tokio = "1.33.0"
|
||||
tokio-util = "0.7.10"
|
||||
tokio-tungstenite = "0.20.1"
|
||||
tracing = "0.1.37"
|
||||
tungstenite = { version = "0.20.1", default-features = false }
|
||||
@@ -172,6 +173,14 @@ utoipa-swagger-ui = "3.1.5"
|
||||
url = "2.4"
|
||||
zeroize = "1.6.0"
|
||||
|
||||
# coconut/DKG related
|
||||
# unfortunately until https://github.com/zkcrypto/bls12_381/issues/10 is resolved, we have to rely on the fork
|
||||
# as we need to be able to serialize Gt so that we could create the lookup table for baby-step-giant-step algorithm
|
||||
bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", branch ="feature/gt-serialization-0.8.0" }
|
||||
group = "0.13.0"
|
||||
ff = "0.13.0"
|
||||
|
||||
|
||||
# cosmwasm-related
|
||||
cosmwasm-derive = "=1.3.0"
|
||||
cosmwasm-schema = "=1.3.0"
|
||||
@@ -192,6 +201,7 @@ cw-controllers = { version = "=1.1.0" }
|
||||
bip32 = "0.5.1"
|
||||
cosmrs = "=0.15.0"
|
||||
tendermint-rpc = "0.34" # same version as used by cosmrs
|
||||
tendermint = "0.34" # same version as used by cosmrs
|
||||
prost = "0.12"
|
||||
|
||||
# wasm-related dependencies
|
||||
|
||||
@@ -5,6 +5,7 @@ authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej St
|
||||
description = "Implementation of the Nym Client"
|
||||
edition = "2021"
|
||||
rust-version = "1.65"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ name = "nym-client-websocket-requests"
|
||||
version = "0.1.0"
|
||||
authors = ["Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
|
||||
edition = "2021"
|
||||
rust-version = "1.56"
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace = true, features = ["cargo", "derive"] }
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
name = "async-file-watcher"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
name = "nym-bandwidth-controller"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -10,6 +11,7 @@ bip39 = { workspace = true }
|
||||
rand = "0.7.3"
|
||||
thiserror = { workspace = true }
|
||||
url = { workspace = true }
|
||||
zeroize = { workspace = true }
|
||||
|
||||
nym-coconut-interface = { path = "../coconut-interface" }
|
||||
nym-credential-storage = { path = "../credential-storage" }
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::error::BandwidthControllerError;
|
||||
use nym_coconut_interface::{Base58, Parameters};
|
||||
use nym_coconut_interface::Base58;
|
||||
use nym_credential_storage::storage::Storage;
|
||||
use nym_credentials::coconut::bandwidth::{BandwidthVoucher, TOTAL_ATTRIBUTES};
|
||||
use nym_credentials::coconut::bandwidth::BandwidthVoucher;
|
||||
use nym_credentials::coconut::utils::obtain_aggregate_signature;
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
use nym_network_defaults::VOUCHER_INFO;
|
||||
@@ -12,10 +12,8 @@ use nym_validator_client::coconut::all_coconut_api_clients;
|
||||
use nym_validator_client::nyxd::contract_traits::CoconutBandwidthSigningClient;
|
||||
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
|
||||
use nym_validator_client::nyxd::Coin;
|
||||
use nym_validator_client::nyxd::Hash;
|
||||
use rand::rngs::OsRng;
|
||||
use state::{KeyPair, State};
|
||||
use std::str::FromStr;
|
||||
use state::State;
|
||||
|
||||
pub mod state;
|
||||
|
||||
@@ -24,30 +22,29 @@ where
|
||||
C: CoconutBandwidthSigningClient + Sync,
|
||||
{
|
||||
let mut rng = OsRng;
|
||||
let signing_keypair = KeyPair::from(identity::KeyPair::new(&mut rng));
|
||||
let encryption_keypair = KeyPair::from(encryption::KeyPair::new(&mut rng));
|
||||
let params = Parameters::new(TOTAL_ATTRIBUTES).unwrap();
|
||||
let signing_key = identity::PrivateKey::new(&mut rng);
|
||||
let encryption_key = encryption::PrivateKey::new(&mut rng);
|
||||
let params = BandwidthVoucher::default_parameters();
|
||||
let voucher_value = amount.amount.to_string();
|
||||
|
||||
let tx_hash = client
|
||||
.deposit(
|
||||
amount,
|
||||
String::from(VOUCHER_INFO),
|
||||
signing_keypair.public_key.clone(),
|
||||
encryption_keypair.public_key.clone(),
|
||||
signing_key.public_key().to_base58_string(),
|
||||
encryption_key.public_key().to_base58_string(),
|
||||
None,
|
||||
)
|
||||
.await?
|
||||
.transaction_hash
|
||||
.to_string();
|
||||
.transaction_hash;
|
||||
|
||||
let voucher = BandwidthVoucher::new(
|
||||
¶ms,
|
||||
voucher_value,
|
||||
VOUCHER_INFO.to_string(),
|
||||
Hash::from_str(&tx_hash).map_err(|_| BandwidthControllerError::InvalidTxHash)?,
|
||||
identity::PrivateKey::from_base58_string(&signing_keypair.private_key)?,
|
||||
encryption::PrivateKey::from_base58_string(&encryption_keypair.private_key)?,
|
||||
tx_hash,
|
||||
signing_key,
|
||||
encryption_key,
|
||||
);
|
||||
|
||||
let state = State { voucher, params };
|
||||
|
||||
@@ -2,32 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use nym_coconut_interface::Parameters;
|
||||
use nym_credentials::coconut::bandwidth::{BandwidthVoucher, TOTAL_ATTRIBUTES};
|
||||
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
|
||||
pub(crate) struct KeyPair {
|
||||
pub public_key: String,
|
||||
pub private_key: String,
|
||||
}
|
||||
|
||||
impl From<identity::KeyPair> for KeyPair {
|
||||
fn from(kp: identity::KeyPair) -> Self {
|
||||
Self {
|
||||
public_key: kp.public_key().to_base58_string(),
|
||||
private_key: kp.private_key().to_base58_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<encryption::KeyPair> for KeyPair {
|
||||
fn from(kp: encryption::KeyPair) -> Self {
|
||||
Self {
|
||||
public_key: kp.public_key().to_base58_string(),
|
||||
private_key: kp.private_key().to_base58_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
use nym_credentials::coconut::bandwidth::BandwidthVoucher;
|
||||
|
||||
pub struct State {
|
||||
pub voucher: BandwidthVoucher,
|
||||
@@ -38,7 +13,7 @@ impl State {
|
||||
pub fn new(voucher: BandwidthVoucher) -> Self {
|
||||
State {
|
||||
voucher,
|
||||
params: Parameters::new(TOTAL_ATTRIBUTES).unwrap(),
|
||||
params: BandwidthVoucher::default_parameters(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ use nym_credential_storage::storage::Storage;
|
||||
use nym_validator_client::coconut::all_coconut_api_clients;
|
||||
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
|
||||
use std::str::FromStr;
|
||||
use zeroize::Zeroizing;
|
||||
use {
|
||||
nym_coconut_interface::Base58,
|
||||
nym_credentials::coconut::{
|
||||
@@ -46,10 +47,12 @@ impl<C, St: Storage> BandwidthController<C, St> {
|
||||
let voucher_value = u64::from_str(&bandwidth_credential.voucher_value)
|
||||
.map_err(|_| StorageError::InconsistentData)?;
|
||||
let voucher_info = bandwidth_credential.voucher_info.clone();
|
||||
let serial_number =
|
||||
nym_coconut_interface::Attribute::try_from_bs58(bandwidth_credential.serial_number)?;
|
||||
let binding_number =
|
||||
nym_coconut_interface::Attribute::try_from_bs58(bandwidth_credential.binding_number)?;
|
||||
let serial_number = Zeroizing::new(nym_coconut_interface::Attribute::try_from_bs58(
|
||||
bandwidth_credential.serial_number,
|
||||
)?);
|
||||
let binding_number = Zeroizing::new(nym_coconut_interface::Attribute::try_from_bs58(
|
||||
bandwidth_credential.binding_number,
|
||||
)?);
|
||||
let signature =
|
||||
nym_coconut_interface::Signature::try_from_bs58(bandwidth_credential.signature)?;
|
||||
let epoch_id = u64::from_str(&bandwidth_credential.epoch_id)
|
||||
@@ -64,8 +67,8 @@ impl<C, St: Storage> BandwidthController<C, St> {
|
||||
prepare_for_spending(
|
||||
voucher_value,
|
||||
voucher_info,
|
||||
serial_number,
|
||||
binding_number,
|
||||
&serial_number,
|
||||
&binding_number,
|
||||
epoch_id,
|
||||
&signature,
|
||||
&verification_key,
|
||||
|
||||
@@ -4,6 +4,7 @@ version = "1.1.15"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
edition = "2021"
|
||||
rust-version = "1.66"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ pub type BatchMixMessageReceiver = tokio::sync::mpsc::Receiver<Vec<MixPacket>>;
|
||||
pub mod transceiver;
|
||||
|
||||
// We remind ourselves that 32 x 32kb = 1024kb, a reasonable size for a network buffer.
|
||||
pub const MIX_MESSAGE_RECEIVER_BUFFER_SIZE: usize = 8;
|
||||
pub const MIX_MESSAGE_RECEIVER_BUFFER_SIZE: usize = 32;
|
||||
const MAX_FAILURE_COUNT: usize = 100;
|
||||
|
||||
// that's also disgusting.
|
||||
|
||||
@@ -158,7 +158,7 @@ pub struct LocalGateway {
|
||||
|
||||
// 'sender' part
|
||||
/// Channel responsible for taking mix packets and forwarding them further into the further mixnet layers.
|
||||
packet_forwarder: mpsc::Sender<MixPacket>,
|
||||
packet_forwarder: mpsc::UnboundedSender<MixPacket>,
|
||||
|
||||
// 'receiver' part
|
||||
packet_router_tx: Option<oneshot::Sender<PacketRouter>>,
|
||||
@@ -168,7 +168,7 @@ pub struct LocalGateway {
|
||||
impl LocalGateway {
|
||||
pub fn new(
|
||||
local_identity: identity::PublicKey,
|
||||
packet_forwarder: mpsc::Sender<MixPacket>,
|
||||
packet_forwarder: mpsc::UnboundedSender<MixPacket>,
|
||||
packet_router_tx: oneshot::Sender<PacketRouter>,
|
||||
) -> Self {
|
||||
LocalGateway {
|
||||
@@ -181,8 +181,6 @@ impl LocalGateway {
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
mod nonwasm_sealed {
|
||||
use futures::SinkExt;
|
||||
|
||||
use super::*;
|
||||
|
||||
impl GatewayTransceiver for LocalGateway {
|
||||
@@ -195,12 +193,9 @@ mod nonwasm_sealed {
|
||||
impl GatewaySender for LocalGateway {
|
||||
async fn send_mix_packet(&mut self, packet: MixPacket) -> Result<(), ErasedGatewayError> {
|
||||
self.packet_forwarder
|
||||
.send(packet)
|
||||
.await
|
||||
.unwrap();
|
||||
Ok(())
|
||||
// .map_err(|err| err.into_send_error())
|
||||
// .map_err(erase_err)
|
||||
.unbounded_send(packet)
|
||||
.map_err(|err| err.into_send_error())
|
||||
.map_err(erase_err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -127,7 +127,9 @@ impl ActionController {
|
||||
.insert(frag_id, (Arc::new(pending_ack), None))
|
||||
.is_some()
|
||||
{
|
||||
panic!("Tried to insert duplicate pending ack")
|
||||
// This used to be a panic, however since we've seen this actually happen in the
|
||||
// wild, let's not take the whole client (and possibly gateway) down because of it.
|
||||
error!("Tried to insert duplicate pending ack! This should not be possible!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -482,7 +482,7 @@ where
|
||||
} else if packets > 0 {
|
||||
log::info!("{status_str}");
|
||||
} else {
|
||||
log::info!("{status_str}");
|
||||
log::debug!("{status_str}");
|
||||
}
|
||||
|
||||
// Send status message to whoever is listening (possibly UI)
|
||||
@@ -498,7 +498,7 @@ where
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
let mut status_timer = tokio::time::interval(Duration::from_secs(1));
|
||||
let mut status_timer = tokio::time::interval(Duration::from_secs(5));
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
|
||||
@@ -259,6 +259,7 @@ pub(super) fn get_specified_gateway(
|
||||
gateways: &[gateway::Node],
|
||||
must_use_tls: bool,
|
||||
) -> Result<gateway::Node, ClientCoreError> {
|
||||
log::debug!("Requesting specified gateway: {}", gateway_identity);
|
||||
let user_gateway = identity::PublicKey::from_base58_string(gateway_identity)
|
||||
.map_err(ClientCoreError::UnableToCreatePublicKeyFromGatewayId)?;
|
||||
|
||||
|
||||
@@ -212,7 +212,7 @@ where
|
||||
D::StorageError: Send + Sync + 'static,
|
||||
T: DeserializeOwned + Serialize + Send + Sync,
|
||||
{
|
||||
log::trace!("Setting up gateway");
|
||||
log::debug!("Setting up gateway");
|
||||
match setup {
|
||||
GatewaySetup::MustLoad => use_loaded_gateway_details(key_store, details_store).await,
|
||||
GatewaySetup::New {
|
||||
|
||||
@@ -3,6 +3,7 @@ name = "nym-gateway-client"
|
||||
version = "0.1.0"
|
||||
authors = ["Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -792,6 +792,7 @@ pub struct InitOnly;
|
||||
impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
|
||||
// for initialisation we do not need credential storage. Though it's still a bit weird we have to set the generic...
|
||||
pub fn new_init(config: GatewayConfig, local_identity: Arc<identity::KeyPair>) -> Self {
|
||||
log::trace!("Initialising gateway client");
|
||||
use futures::channel::mpsc;
|
||||
|
||||
// note: this packet_router is completely invalid in normal circumstances, but "works"
|
||||
|
||||
@@ -3,14 +3,15 @@ name = "nym-mixnet-client"
|
||||
version = "0.1.0"
|
||||
authors = ["Jedrzej Stuczynski <andrew@nymtech.net>"]
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
futures = { workspace = true }
|
||||
log = { workspace = true }
|
||||
tokio = { version = "1.24.1", features = ["time", "net", "rt"] }
|
||||
tokio-util = { version = "0.7.4", features = ["codec"] }
|
||||
tokio = { workspace = true, features = ["time", "net", "rt"] }
|
||||
tokio-util = { workspace = true, features = ["codec"] }
|
||||
|
||||
# internal
|
||||
nym-sphinx = { path = "../../nymsphinx" }
|
||||
|
||||
@@ -8,8 +8,8 @@ use log::*;
|
||||
use nym_sphinx::forwarding::packet::MixPacket;
|
||||
use std::time::Duration;
|
||||
|
||||
pub type MixForwardingSender = mpsc::Sender<MixPacket>;
|
||||
type MixForwardingReceiver = mpsc::Receiver<MixPacket>;
|
||||
pub type MixForwardingSender = mpsc::UnboundedSender<MixPacket>;
|
||||
type MixForwardingReceiver = mpsc::UnboundedReceiver<MixPacket>;
|
||||
|
||||
/// A specialisation of client such that it forwards any received packets on the channel into the
|
||||
/// mix network immediately, i.e. will not try to listen for any responses.
|
||||
@@ -36,8 +36,7 @@ impl PacketForwarder {
|
||||
use_legacy_version,
|
||||
);
|
||||
|
||||
// let (packet_sender, packet_receiver) = mpsc::unbounded();
|
||||
let (packet_sender, packet_receiver) = mpsc::channel(8);
|
||||
let (packet_sender, packet_receiver) = mpsc::unbounded();
|
||||
|
||||
(
|
||||
PacketForwarder {
|
||||
|
||||
@@ -4,6 +4,7 @@ version = "0.1.0"
|
||||
authors = ["Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
edition = "2021"
|
||||
rust-version = "1.56"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -5,8 +5,12 @@ use crate::nym_api::error::NymAPIError;
|
||||
use crate::nym_api::routes::{CORE_STATUS_COUNT, SINCE_ARG};
|
||||
use async_trait::async_trait;
|
||||
use http_api_client::{ApiClient, NO_PARAMS};
|
||||
use nym_api_requests::coconut::models::{
|
||||
EpochCredentialsResponse, IssuedCredentialResponse, IssuedCredentialsResponse,
|
||||
};
|
||||
use nym_api_requests::coconut::{
|
||||
BlindSignRequestBody, BlindedSignatureResponse, VerifyCredentialBody, VerifyCredentialResponse,
|
||||
BlindSignRequestBody, BlindedSignatureResponse, CredentialsRequestBody, VerifyCredentialBody,
|
||||
VerifyCredentialResponse,
|
||||
};
|
||||
use nym_api_requests::models::{
|
||||
ComputeRewardEstParam, DescribedGateway, GatewayBondAnnotated, GatewayCoreStatusResponse,
|
||||
@@ -15,6 +19,7 @@ use nym_api_requests::models::{
|
||||
MixnodeStatusResponse, MixnodeUptimeHistoryResponse, RewardEstimationResponse,
|
||||
StakeSaturationResponse, UptimeResponse,
|
||||
};
|
||||
use nym_coconut_dkg_common::types::EpochId;
|
||||
use nym_mixnet_contract_common::mixnode::MixNodeDetails;
|
||||
use nym_mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixId};
|
||||
use nym_name_service_common::response::NamesListResponse;
|
||||
@@ -399,6 +404,60 @@ pub trait NymApiClientExt: ApiClient {
|
||||
.await
|
||||
}
|
||||
|
||||
async fn epoch_credentials(
|
||||
&self,
|
||||
dkg_epoch: EpochId,
|
||||
) -> Result<EpochCredentialsResponse, NymAPIError> {
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::COCONUT_ROUTES,
|
||||
routes::BANDWIDTH,
|
||||
routes::COCONUT_EPOCH_CREDENTIALS,
|
||||
&dkg_epoch.to_string(),
|
||||
],
|
||||
NO_PARAMS,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn issued_credential(
|
||||
&self,
|
||||
credential_id: i64,
|
||||
) -> Result<IssuedCredentialResponse, NymAPIError> {
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::COCONUT_ROUTES,
|
||||
routes::BANDWIDTH,
|
||||
routes::COCONUT_ISSUED_CREDENTIAL,
|
||||
&credential_id.to_string(),
|
||||
],
|
||||
NO_PARAMS,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn issued_credentials(
|
||||
&self,
|
||||
credential_ids: Vec<i64>,
|
||||
) -> Result<IssuedCredentialsResponse, NymAPIError> {
|
||||
self.post_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::COCONUT_ROUTES,
|
||||
routes::BANDWIDTH,
|
||||
routes::COCONUT_ISSUED_CREDENTIALS,
|
||||
],
|
||||
NO_PARAMS,
|
||||
&CredentialsRequestBody {
|
||||
credential_ids,
|
||||
pagination: None,
|
||||
},
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_service_providers(&self) -> Result<ServicesListResponse, NymAPIError> {
|
||||
log::trace!("Getting service providers");
|
||||
self.get_json(&[routes::API_VERSION, routes::SERVICE_PROVIDERS], NO_PARAMS)
|
||||
|
||||
@@ -17,6 +17,9 @@ pub const BANDWIDTH: &str = "bandwidth";
|
||||
|
||||
pub const COCONUT_BLIND_SIGN: &str = "blind-sign";
|
||||
pub const COCONUT_VERIFY_BANDWIDTH_CREDENTIAL: &str = "verify-bandwidth-credential";
|
||||
pub const COCONUT_EPOCH_CREDENTIALS: &str = "epoch-credentials";
|
||||
pub const COCONUT_ISSUED_CREDENTIAL: &str = "issued-credential";
|
||||
pub const COCONUT_ISSUED_CREDENTIALS: &str = "issued-credentials";
|
||||
|
||||
pub const STATUS_ROUTES: &str = "status";
|
||||
pub const MIXNODE: &str = "mixnode";
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ pub trait CoconutBandwidthSigningClient {
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
let req = CoconutBandwidthExecuteMsg::DepositFunds {
|
||||
data: DepositData::new(info.to_string(), verification_key, encryption_key),
|
||||
data: DepositData::new(info, verification_key, encryption_key),
|
||||
};
|
||||
self.execute_coconut_bandwidth_contract(
|
||||
fee,
|
||||
|
||||
+22
-2
@@ -6,8 +6,8 @@ use crate::nyxd::error::NyxdError;
|
||||
use crate::nyxd::CosmWasmClient;
|
||||
use async_trait::async_trait;
|
||||
use cw3::{
|
||||
ProposalListResponse, ProposalResponse, VoteListResponse, VoteResponse, VoterListResponse,
|
||||
VoterResponse,
|
||||
ProposalListResponse, ProposalResponse, VoteListResponse, VoteResponse, VoterDetail,
|
||||
VoterListResponse, VoterResponse,
|
||||
};
|
||||
use cw_utils::ThresholdResponse;
|
||||
use nym_multisig_contract_common::msg::QueryMsg as MultisigQueryMsg;
|
||||
@@ -114,6 +114,26 @@ pub trait PagedMultisigQueryClient: MultisigQueryClient {
|
||||
|
||||
Ok(proposals)
|
||||
}
|
||||
|
||||
async fn get_all_voters(&self) -> Result<Vec<VoterDetail>, NyxdError> {
|
||||
let mut voters = Vec::new();
|
||||
let mut start_after = None;
|
||||
|
||||
loop {
|
||||
let mut paged_response = self.list_voters(start_after.take(), None).await?;
|
||||
|
||||
let last_voter = paged_response.voters.last().map(|prop| prop.addr.clone());
|
||||
voters.append(&mut paged_response.voters);
|
||||
|
||||
if let Some(start_after_res) = last_voter {
|
||||
start_after = Some(start_after_res)
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(voters)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::nyxd::TxResponse;
|
||||
|
||||
pub fn find_tx_attribute(tx: &TxResponse, event_type: &str, attribute_key: &str) -> Option<String> {
|
||||
let event = tx.tx_result.events.iter().find(|e| e.kind == event_type)?;
|
||||
let attribute = event
|
||||
.attributes
|
||||
.iter()
|
||||
.find(|attr| attr.key == attribute_key)?;
|
||||
Some(attribute.value.clone())
|
||||
}
|
||||
@@ -47,6 +47,10 @@ pub use cosmrs::Coin as CosmosCoin;
|
||||
pub use cosmrs::Gas;
|
||||
pub use cosmrs::{bip32, AccountId, Denom};
|
||||
pub use cosmwasm_std::Coin as CosmWasmCoin;
|
||||
pub use cw2;
|
||||
pub use cw3;
|
||||
pub use cw4;
|
||||
pub use cw_controllers;
|
||||
pub use fee::{gas_price::GasPrice, GasAdjustable, GasAdjustment};
|
||||
pub use tendermint_rpc::{
|
||||
endpoint::{tx::Response as TxResponse, validators::Response as ValidatorResponse},
|
||||
@@ -67,6 +71,7 @@ pub mod contract_traits;
|
||||
pub mod cosmwasm_client;
|
||||
pub mod error;
|
||||
pub mod fee;
|
||||
pub mod helpers;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Config {
|
||||
@@ -376,7 +381,11 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn simulate<I, M>(&self, messages: I) -> Result<SimulateResponse, NyxdError>
|
||||
pub async fn simulate<I, M>(
|
||||
&self,
|
||||
messages: I,
|
||||
memo: impl Into<String> + Send + 'static,
|
||||
) -> Result<SimulateResponse, NyxdError>
|
||||
where
|
||||
I: IntoIterator<Item = M> + Send,
|
||||
M: Msg,
|
||||
@@ -391,7 +400,7 @@ where
|
||||
.map_err(|_| {
|
||||
NyxdError::SerializationError("custom simulate messages".to_owned())
|
||||
})?,
|
||||
"simulating execution of transactions",
|
||||
memo,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ name = "nym-coconut-interface"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
description = "Crutch library until there is proper SerDe support for coconut structs"
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
bs58 = "0.4.0"
|
||||
|
||||
@@ -21,10 +21,14 @@ pub use nym_coconut::{
|
||||
pub struct Credential {
|
||||
#[getset(get = "pub")]
|
||||
n_params: u32,
|
||||
|
||||
#[getset(get = "pub")]
|
||||
theta: Theta,
|
||||
|
||||
voucher_value: u64,
|
||||
|
||||
voucher_info: String,
|
||||
|
||||
#[getset(get = "pub")]
|
||||
epoch_id: u64,
|
||||
}
|
||||
@@ -64,14 +68,12 @@ impl Credential {
|
||||
|
||||
pub fn verify(&self, verification_key: &VerificationKey) -> bool {
|
||||
let params = Parameters::new(self.n_params).unwrap();
|
||||
let public_attributes = [
|
||||
self.voucher_value.to_string().as_bytes(),
|
||||
self.voucher_info.as_bytes(),
|
||||
]
|
||||
.iter()
|
||||
.map(hash_to_scalar)
|
||||
.collect::<Vec<Attribute>>();
|
||||
nym_coconut::verify_credential(¶ms, verification_key, &self.theta, &public_attributes)
|
||||
|
||||
let hashed_value = hash_to_scalar(self.voucher_value.to_string());
|
||||
let hashed_info = hash_to_scalar(&self.voucher_info);
|
||||
let public_attributes = &[&hashed_value, &hashed_info];
|
||||
|
||||
nym_coconut::verify_credential(¶ms, verification_key, &self.theta, public_attributes)
|
||||
}
|
||||
|
||||
pub fn as_bytes(&self) -> Vec<u8> {
|
||||
@@ -180,8 +182,8 @@ mod tests {
|
||||
¶ms,
|
||||
&verification_key,
|
||||
&signature,
|
||||
serial_number,
|
||||
binding_number,
|
||||
&serial_number,
|
||||
&binding_number,
|
||||
)
|
||||
.unwrap();
|
||||
let credential = Credential::new(4, theta, voucher_value, voucher_info, 42);
|
||||
|
||||
@@ -3,6 +3,7 @@ name = "nym-cli-commands"
|
||||
version = "1.0.0"
|
||||
authors.workspace = true
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
|
||||
@@ -26,6 +26,10 @@ pub struct Args {
|
||||
}
|
||||
|
||||
pub async fn execute(args: Args, client: SigningClient) -> anyhow::Result<()> {
|
||||
if args.amount == 0 {
|
||||
bail!("did not specify credential amount")
|
||||
}
|
||||
|
||||
let loaded = CommonConfigsWrapper::try_load(args.client_config)?;
|
||||
|
||||
if let Ok(id) = loaded.try_get_id() {
|
||||
|
||||
@@ -3,6 +3,7 @@ name = "nym-config"
|
||||
version = "0.1.0"
|
||||
authors = ["Jedrzej Stuczynski <andrew@nymtech.net>"]
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -17,4 +18,4 @@ url = { workspace = true }
|
||||
nym-network-defaults = { path = "../network-defaults" }
|
||||
|
||||
[features]
|
||||
default = ["dirs"]
|
||||
default = ["dirs"]
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
name = "nym-coconut-bandwidth-contract-common"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -12,4 +13,4 @@ cw2 = { workspace = true, optional = true }
|
||||
nym-multisig-contract-common = { path = "../multisig-contract" }
|
||||
|
||||
[features]
|
||||
schema = ["cw2"]
|
||||
schema = ["cw2"]
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
// event types
|
||||
pub const DEPOSITED_FUNDS_EVENT_TYPE: &str = "deposited-funds";
|
||||
|
||||
// a 'wasm-' prefix is added to all cosmwasm events
|
||||
pub const COSMWASM_DEPOSITED_FUNDS_EVENT_TYPE: &str = "wasm-deposited-funds";
|
||||
|
||||
// attributes that are used in multiple places
|
||||
pub const DEPOSIT_VALUE: &str = "deposit-value";
|
||||
pub const DEPOSIT_INFO: &str = "deposit-info";
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
name = "nym-coconut-dkg-common"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -14,4 +15,4 @@ contracts-common = { path = "../contracts-common", package = "nym-contracts-comm
|
||||
nym-multisig-contract-common = { path = "../multisig-contract" }
|
||||
|
||||
[features]
|
||||
schema = []
|
||||
schema = []
|
||||
|
||||
@@ -174,17 +174,19 @@ impl Display for EpochState {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
EpochState::PublicKeySubmission { resharing } => {
|
||||
write!(f, "PublicKeySubmission with resharing {resharing}")
|
||||
write!(f, "PublicKeySubmission (resharing: {resharing})")
|
||||
}
|
||||
EpochState::DealingExchange { resharing } => {
|
||||
write!(f, "DealingExchange (resharing: {resharing})")
|
||||
}
|
||||
EpochState::DealingExchange { resharing } => write!(f, "DealingExchange {resharing}"),
|
||||
EpochState::VerificationKeySubmission { resharing } => {
|
||||
write!(f, "VerificationKeySubmission with resharing {resharing}")
|
||||
write!(f, "VerificationKeySubmission (resharing: {resharing})")
|
||||
}
|
||||
EpochState::VerificationKeyValidation { resharing } => {
|
||||
write!(f, "VerificationKeyValidation with resharing {resharing}")
|
||||
write!(f, "VerificationKeyValidation (resharing: {resharing})")
|
||||
}
|
||||
EpochState::VerificationKeyFinalization { resharing } => {
|
||||
write!(f, "VerificationKeyFinalization with resharing {resharing}")
|
||||
write!(f, "VerificationKeyFinalization (resharing: {resharing})")
|
||||
}
|
||||
EpochState::InProgress => write!(f, "InProgress"),
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
name = "nym-ephemera-common"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -13,4 +14,4 @@ cw-utils = { workspace = true }
|
||||
contracts-common = { path = "../contracts-common", package = "nym-contracts-common" }
|
||||
|
||||
[features]
|
||||
schema = []
|
||||
schema = []
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
name = "nym-group-contract-common"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
name = "nym-multisig-contract-common"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
name = "nym-name-service-common"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -16,4 +17,4 @@ serde = { workspace = true, features = ["derive"] }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
[features]
|
||||
schema = ["cw2"]
|
||||
schema = ["cw2"]
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
name = "nym-service-provider-directory-common"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -15,4 +16,4 @@ nym-contracts-common = { path = "../contracts-common", version = "0.5.0" }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
[features]
|
||||
schema = ["cw2"]
|
||||
schema = ["cw2"]
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
name = "nym-credential-storage"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
name = "nym-credential-utils"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -2,18 +2,20 @@
|
||||
name = "nym-credentials"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
bls12_381 = { version = "0.5", default-features = false, features = ["pairings", "alloc", "experimental"] }
|
||||
bls12_381 = { workspace = true, default-features = false, features = ["pairings", "alloc", "experimental"] }
|
||||
cosmrs = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
log = { workspace = true }
|
||||
zeroize = { workspace = true }
|
||||
|
||||
# I guess temporarily until we get serde support in coconut up and running
|
||||
nym-coconut-interface = { path = "../coconut-interface" }
|
||||
nym-crypto = { path = "../crypto", features = ["rand", "asymmetric", "symmetric", "hashing"] }
|
||||
nym-crypto = { path = "../crypto", features = ["rand", "asymmetric"] }
|
||||
nym-api-requests = { path = "../../nym-api/nym-api-requests" }
|
||||
nym-validator-client = { path = "../client-libs/validator-client", default-features = false }
|
||||
|
||||
|
||||
@@ -13,38 +13,60 @@ use nym_coconut_interface::{
|
||||
PrivateAttribute, PublicAttribute, Signature, VerificationKey,
|
||||
};
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||
|
||||
use super::utils::prepare_credential_for_spending;
|
||||
use crate::error::Error;
|
||||
|
||||
pub const PUBLIC_ATTRIBUTES: u32 = 2;
|
||||
pub const PRIVATE_ATTRIBUTES: u32 = 2;
|
||||
pub const TOTAL_ATTRIBUTES: u32 = PUBLIC_ATTRIBUTES + PRIVATE_ATTRIBUTES;
|
||||
|
||||
#[derive(Zeroize, ZeroizeOnDrop)]
|
||||
pub struct BandwidthVoucher {
|
||||
// a random secret value generated by the client used for double-spending detection
|
||||
// private attributes
|
||||
/// a random secret value generated by the client used for double-spending detection
|
||||
serial_number: PrivateAttribute,
|
||||
// a random secret value generated by the client used to bind multiple credentials together
|
||||
|
||||
/// a random secret value generated by the client used to bind multiple credentials together
|
||||
binding_number: PrivateAttribute,
|
||||
// the value (e.g., bandwidth) encoded in this voucher
|
||||
voucher_value: PublicAttribute,
|
||||
// the plain text value (e.g., bandwidth) encoded in this voucher
|
||||
|
||||
// public atttributes:
|
||||
/// the plain text value (e.g., bandwidth) encoded in this voucher
|
||||
// TODO: in another PR change the value from `"1000"` to `"1000unym"`
|
||||
voucher_value_plain: String,
|
||||
// a field with public information, e.g., type of voucher, interval etc.
|
||||
voucher_info: PublicAttribute,
|
||||
// the plain text information
|
||||
|
||||
/// the plain text information
|
||||
voucher_info_plain: String,
|
||||
// the hash of the deposit transaction
|
||||
|
||||
/// the precomputed value (e.g., bandwidth) encoded in this voucher
|
||||
_voucher_value_prehashed: PublicAttribute,
|
||||
|
||||
/// the precomputed field with public information, e.g., type of voucher, interval etc.
|
||||
_voucher_info_prehashed: PublicAttribute,
|
||||
|
||||
/// the hash of the deposit transaction
|
||||
#[zeroize(skip)]
|
||||
tx_hash: Hash,
|
||||
// base58 encoded private key ensuring the depositer requested these attributes
|
||||
|
||||
/// base58 encoded private key ensuring the depositer requested these attributes
|
||||
signing_key: identity::PrivateKey,
|
||||
// base58 encoded private key ensuring only this client receives the signature share
|
||||
encryption_key: encryption::PrivateKey,
|
||||
|
||||
/// base58 encoded private key ensuring only this client receives the signature share
|
||||
unused_ed25519: encryption::PrivateKey,
|
||||
|
||||
pedersen_commitments_openings: Vec<Attribute>,
|
||||
|
||||
#[zeroize(skip)]
|
||||
blind_sign_request: BlindSignRequest,
|
||||
}
|
||||
|
||||
impl BandwidthVoucher {
|
||||
pub const PUBLIC_ATTRIBUTES: u32 = 2;
|
||||
pub const PRIVATE_ATTRIBUTES: u32 = 2;
|
||||
pub const ENCODED_ATTRIBUTES: u32 = 4;
|
||||
|
||||
pub fn default_parameters() -> Parameters {
|
||||
// safety: the unwrap is fine here as Self::ENCODED_ATTRIBUTES is non-zero
|
||||
Parameters::new(Self::ENCODED_ATTRIBUTES).unwrap()
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
params: &Parameters,
|
||||
voucher_value: String,
|
||||
@@ -57,24 +79,26 @@ impl BandwidthVoucher {
|
||||
let binding_number = params.random_scalar();
|
||||
let voucher_value_plain = voucher_value.clone();
|
||||
let voucher_info_plain = voucher_info.clone();
|
||||
let voucher_value = hash_to_scalar(voucher_value.as_bytes());
|
||||
let voucher_info = hash_to_scalar(voucher_info.as_bytes());
|
||||
|
||||
let _voucher_value_prehashed = hash_to_scalar(voucher_value);
|
||||
let _voucher_info_prehashed = hash_to_scalar(voucher_info);
|
||||
|
||||
let (pedersen_commitments_openings, blind_sign_request) = prepare_blind_sign(
|
||||
params,
|
||||
&[serial_number, binding_number],
|
||||
&[voucher_value, voucher_info],
|
||||
&[&serial_number, &binding_number],
|
||||
&[&_voucher_value_prehashed, &_voucher_info_prehashed],
|
||||
)
|
||||
.unwrap();
|
||||
BandwidthVoucher {
|
||||
serial_number,
|
||||
binding_number,
|
||||
voucher_value,
|
||||
_voucher_value_prehashed,
|
||||
voucher_value_plain,
|
||||
voucher_info,
|
||||
_voucher_info_prehashed,
|
||||
voucher_info_plain,
|
||||
tx_hash,
|
||||
signing_key,
|
||||
encryption_key,
|
||||
unused_ed25519: encryption_key,
|
||||
pedersen_commitments_openings,
|
||||
blind_sign_request,
|
||||
}
|
||||
@@ -87,7 +111,7 @@ impl BandwidthVoucher {
|
||||
let voucher_info_plain_b = self.voucher_info_plain.as_bytes();
|
||||
let tx_hash_b = self.tx_hash.as_bytes();
|
||||
let signing_key_b = self.signing_key.to_bytes();
|
||||
let encryption_key_b = self.encryption_key.to_bytes();
|
||||
let encryption_key_b = self.unused_ed25519.to_bytes();
|
||||
let blind_sign_request_b = self.blind_sign_request.to_bytes();
|
||||
|
||||
let mut ret = Vec::new();
|
||||
@@ -171,13 +195,13 @@ impl BandwidthVoucher {
|
||||
bytes[var_length_pointer..var_length_pointer + voucher_value_plain_no].to_vec(),
|
||||
)
|
||||
.or_else(utf_err)?;
|
||||
let voucher_value = hash_to_scalar(&voucher_value_plain);
|
||||
let _voucher_value_prehashed = hash_to_scalar(&voucher_value_plain);
|
||||
var_length_pointer += voucher_value_plain_no;
|
||||
let voucher_info_plain = String::from_utf8(
|
||||
bytes[var_length_pointer..var_length_pointer + voucher_info_plain_no].to_vec(),
|
||||
)
|
||||
.or_else(utf_err)?;
|
||||
let voucher_info = hash_to_scalar(&voucher_info_plain);
|
||||
let _voucher_info_prehashed = hash_to_scalar(&voucher_info_plain);
|
||||
var_length_pointer += voucher_info_plain_no;
|
||||
let blind_sign_request = BlindSignRequest::from_bytes(
|
||||
&bytes[var_length_pointer..var_length_pointer + blind_sign_request_no],
|
||||
@@ -196,36 +220,43 @@ impl BandwidthVoucher {
|
||||
Ok(Self {
|
||||
serial_number,
|
||||
binding_number,
|
||||
voucher_value,
|
||||
_voucher_value_prehashed,
|
||||
voucher_value_plain,
|
||||
voucher_info,
|
||||
_voucher_info_prehashed,
|
||||
voucher_info_plain,
|
||||
tx_hash,
|
||||
signing_key,
|
||||
encryption_key,
|
||||
unused_ed25519: encryption_key,
|
||||
pedersen_commitments_openings,
|
||||
blind_sign_request,
|
||||
})
|
||||
}
|
||||
|
||||
/// Check if the plain values correspond to the PublicAttributes
|
||||
pub fn verify_against_plain(values: &[PublicAttribute], plain_values: &[String]) -> bool {
|
||||
pub fn verify_against_plain(values: &[&PublicAttribute], plain_values: &[String]) -> bool {
|
||||
values.len() == 2
|
||||
&& plain_values.len() == 2
|
||||
&& values[0] == hash_to_scalar(&plain_values[0])
|
||||
&& values[1] == hash_to_scalar(&plain_values[1])
|
||||
&& values[0] == &hash_to_scalar(&plain_values[0])
|
||||
&& values[1] == &hash_to_scalar(&plain_values[1])
|
||||
}
|
||||
|
||||
pub fn tx_hash(&self) -> &Hash {
|
||||
&self.tx_hash
|
||||
pub fn tx_hash(&self) -> Hash {
|
||||
self.tx_hash
|
||||
}
|
||||
|
||||
pub fn get_public_attributes(&self) -> Vec<PublicAttribute> {
|
||||
vec![self.voucher_value, self.voucher_info]
|
||||
pub fn get_public_attributes(&self) -> Vec<&PublicAttribute> {
|
||||
vec![
|
||||
&self._voucher_value_prehashed,
|
||||
&self._voucher_info_prehashed,
|
||||
]
|
||||
}
|
||||
|
||||
pub fn identity_key(&self) -> &identity::PrivateKey {
|
||||
&self.signing_key
|
||||
}
|
||||
|
||||
pub fn encryption_key(&self) -> &encryption::PrivateKey {
|
||||
&self.encryption_key
|
||||
&self.unused_ed25519
|
||||
}
|
||||
|
||||
pub fn pedersen_commitments_openings(&self) -> &Vec<Attribute> {
|
||||
@@ -247,27 +278,32 @@ impl BandwidthVoucher {
|
||||
]
|
||||
}
|
||||
|
||||
pub fn get_private_attributes(&self) -> Vec<PrivateAttribute> {
|
||||
vec![self.serial_number, self.binding_number]
|
||||
pub fn get_private_attributes(&self) -> Vec<&PrivateAttribute> {
|
||||
vec![&self.serial_number, &self.binding_number]
|
||||
}
|
||||
|
||||
pub fn sign(&self, request: &BlindSignRequest) -> identity::Signature {
|
||||
pub fn signable_plaintext(request: &BlindSignRequest, tx_hash: Hash) -> Vec<u8> {
|
||||
let mut message = request.to_bytes();
|
||||
message.extend_from_slice(self.tx_hash.to_string().as_bytes());
|
||||
self.signing_key.sign(&message)
|
||||
message.extend_from_slice(tx_hash.as_bytes());
|
||||
message
|
||||
}
|
||||
|
||||
pub fn sign(&self) -> identity::Signature {
|
||||
let message = Self::signable_plaintext(&self.blind_sign_request, self.tx_hash);
|
||||
self.signing_key.sign(message)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prepare_for_spending(
|
||||
voucher_value: u64,
|
||||
voucher_info: String,
|
||||
serial_number: PrivateAttribute,
|
||||
binding_number: PrivateAttribute,
|
||||
serial_number: &PrivateAttribute,
|
||||
binding_number: &PrivateAttribute,
|
||||
epoch_id: u64,
|
||||
signature: &Signature,
|
||||
verification_key: &VerificationKey,
|
||||
) -> Result<Credential, Error> {
|
||||
let params = Parameters::new(TOTAL_ATTRIBUTES)?;
|
||||
let params = Parameters::new(BandwidthVoucher::ENCODED_ATTRIBUTES)?;
|
||||
|
||||
prepare_credential_for_spending(
|
||||
¶ms,
|
||||
@@ -316,24 +352,30 @@ mod test {
|
||||
let deserialized_voucher = BandwidthVoucher::try_from_bytes(&bytes).unwrap();
|
||||
assert_eq!(voucher.serial_number, deserialized_voucher.serial_number);
|
||||
assert_eq!(voucher.binding_number, deserialized_voucher.binding_number);
|
||||
assert_eq!(voucher.voucher_value, deserialized_voucher.voucher_value);
|
||||
assert_eq!(
|
||||
voucher.voucher_value_plain,
|
||||
deserialized_voucher.voucher_value_plain
|
||||
);
|
||||
assert_eq!(voucher.voucher_info, deserialized_voucher.voucher_info);
|
||||
assert_eq!(
|
||||
voucher.voucher_info_plain,
|
||||
deserialized_voucher.voucher_info_plain
|
||||
);
|
||||
assert_eq!(
|
||||
voucher._voucher_value_prehashed,
|
||||
deserialized_voucher._voucher_value_prehashed
|
||||
);
|
||||
assert_eq!(
|
||||
voucher._voucher_info_prehashed,
|
||||
deserialized_voucher._voucher_info_prehashed
|
||||
);
|
||||
assert_eq!(voucher.tx_hash, deserialized_voucher.tx_hash);
|
||||
assert_eq!(
|
||||
voucher.signing_key.to_string(),
|
||||
deserialized_voucher.signing_key.to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
voucher.encryption_key.to_string(),
|
||||
deserialized_voucher.encryption_key.to_string()
|
||||
voucher.unused_ed25519.to_string(),
|
||||
deserialized_voucher.unused_ed25519.to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
voucher.pedersen_commitments_openings,
|
||||
@@ -371,11 +413,11 @@ mod test {
|
||||
]
|
||||
));
|
||||
assert!(!BandwidthVoucher::verify_against_plain(
|
||||
&[voucher.get_public_attributes()[0], Attribute::one()],
|
||||
&[voucher.get_public_attributes()[0], &Attribute::one()],
|
||||
&voucher.get_public_attributes_plain()
|
||||
));
|
||||
assert!(!BandwidthVoucher::verify_against_plain(
|
||||
&[Attribute::one(), voucher.get_public_attributes()[1]],
|
||||
&[&Attribute::one(), voucher.get_public_attributes()[1]],
|
||||
&voucher.get_public_attributes_plain()
|
||||
));
|
||||
assert!(BandwidthVoucher::verify_against_plain(
|
||||
|
||||
@@ -2,5 +2,4 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub mod bandwidth;
|
||||
pub mod params;
|
||||
pub mod utils;
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use nym_crypto::aes::Aes128;
|
||||
use nym_crypto::blake3;
|
||||
use nym_crypto::ctr;
|
||||
|
||||
type Aes128Ctr = ctr::Ctr64LE<Aes128>;
|
||||
|
||||
/// Hashing algorithm used during hkdf for ephemeral shared key generation per blinded signature
|
||||
/// response encryption.
|
||||
pub type NymApiCredentialHkdfAlgorithm = blake3::Hasher;
|
||||
|
||||
/// Encryption algorithm used for end-to-end encryption of blinded signature response
|
||||
pub type NymApiCredentialEncryptionAlgorithm = Aes128Ctr;
|
||||
@@ -1,18 +1,14 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::coconut::bandwidth::{BandwidthVoucher, PRIVATE_ATTRIBUTES, PUBLIC_ATTRIBUTES};
|
||||
use crate::coconut::params::{NymApiCredentialEncryptionAlgorithm, NymApiCredentialHkdfAlgorithm};
|
||||
use crate::coconut::bandwidth::BandwidthVoucher;
|
||||
use crate::error::Error;
|
||||
use log::{debug, warn};
|
||||
use nym_api_requests::coconut::BlindSignRequestBody;
|
||||
use nym_coconut_interface::{
|
||||
aggregate_signature_shares, aggregate_verification_keys, prove_bandwidth_credential, Attribute,
|
||||
BlindedSignature, Credential, Parameters, Signature, SignatureShare, VerificationKey,
|
||||
Credential, Parameters, Signature, SignatureShare, VerificationKey,
|
||||
};
|
||||
use nym_crypto::asymmetric::encryption::PublicKey;
|
||||
use nym_crypto::shared_key::recompute_shared_key;
|
||||
use nym_crypto::symmetric::stream_cipher;
|
||||
use nym_validator_client::client::CoconutApiClient;
|
||||
|
||||
pub async fn obtain_aggregate_verification_key(
|
||||
@@ -36,47 +32,34 @@ pub async fn obtain_aggregate_verification_key(
|
||||
|
||||
async fn obtain_partial_credential(
|
||||
params: &Parameters,
|
||||
attributes: &BandwidthVoucher,
|
||||
voucher: &BandwidthVoucher,
|
||||
client: &nym_validator_client::client::NymApiClient,
|
||||
validator_vk: &VerificationKey,
|
||||
) -> Result<Signature, Error> {
|
||||
let public_attributes = attributes.get_public_attributes();
|
||||
let public_attributes_plain = attributes.get_public_attributes_plain();
|
||||
let private_attributes = attributes.get_private_attributes();
|
||||
let blind_sign_request = attributes.blind_sign_request();
|
||||
let public_attributes_plain = voucher.get_public_attributes_plain();
|
||||
let blind_sign_request = voucher.blind_sign_request();
|
||||
let request_signature = voucher.sign();
|
||||
|
||||
let blind_sign_request_body = BlindSignRequestBody::new(
|
||||
blind_sign_request,
|
||||
attributes.tx_hash().to_string(),
|
||||
attributes.sign(blind_sign_request).to_base58_string(),
|
||||
&public_attributes,
|
||||
blind_sign_request.clone(),
|
||||
voucher.tx_hash(),
|
||||
request_signature,
|
||||
public_attributes_plain,
|
||||
(public_attributes.len() + private_attributes.len()) as u32,
|
||||
);
|
||||
let response = client.blind_sign(&blind_sign_request_body).await?;
|
||||
let encrypted_signature = response.encrypted_signature;
|
||||
let remote_key = PublicKey::from_bytes(&response.remote_key)?;
|
||||
|
||||
let encryption_key = recompute_shared_key::<
|
||||
NymApiCredentialEncryptionAlgorithm,
|
||||
NymApiCredentialHkdfAlgorithm,
|
||||
>(&remote_key, attributes.encryption_key());
|
||||
let zero_iv = stream_cipher::zero_iv::<NymApiCredentialEncryptionAlgorithm>();
|
||||
let blinded_signature_bytes = stream_cipher::decrypt::<NymApiCredentialEncryptionAlgorithm>(
|
||||
&encryption_key,
|
||||
&zero_iv,
|
||||
&encrypted_signature,
|
||||
);
|
||||
let blinded_signature = response.blinded_signature;
|
||||
|
||||
let blinded_signature = BlindedSignature::from_bytes(&blinded_signature_bytes)?;
|
||||
let public_attributes = voucher.get_public_attributes();
|
||||
let private_attributes = voucher.get_private_attributes();
|
||||
|
||||
let unblinded_signature = blinded_signature.unblind(
|
||||
let unblinded_signature = blinded_signature.unblind_and_verify(
|
||||
params,
|
||||
validator_vk,
|
||||
&private_attributes,
|
||||
&public_attributes,
|
||||
&blind_sign_request.get_commitment_hash(),
|
||||
attributes.pedersen_commitments_openings(),
|
||||
voucher.pedersen_commitments_openings(),
|
||||
)?;
|
||||
|
||||
Ok(unblinded_signature)
|
||||
@@ -84,16 +67,13 @@ async fn obtain_partial_credential(
|
||||
|
||||
pub async fn obtain_aggregate_signature(
|
||||
params: &Parameters,
|
||||
attributes: &BandwidthVoucher,
|
||||
voucher: &BandwidthVoucher,
|
||||
coconut_api_clients: &[CoconutApiClient],
|
||||
threshold: u64,
|
||||
) -> Result<Signature, Error> {
|
||||
if coconut_api_clients.is_empty() {
|
||||
return Err(Error::NoValidatorsAvailable);
|
||||
}
|
||||
let public_attributes = attributes.get_public_attributes();
|
||||
let private_attributes = attributes.get_private_attributes();
|
||||
|
||||
let mut shares = Vec::with_capacity(coconut_api_clients.len());
|
||||
let validators_partial_vks: Vec<_> = coconut_api_clients
|
||||
.iter()
|
||||
@@ -114,7 +94,7 @@ pub async fn obtain_aggregate_signature(
|
||||
|
||||
match obtain_partial_credential(
|
||||
params,
|
||||
attributes,
|
||||
voucher,
|
||||
&coconut_api_client.api_client,
|
||||
&coconut_api_client.verification_key,
|
||||
)
|
||||
@@ -136,6 +116,9 @@ pub async fn obtain_aggregate_signature(
|
||||
return Err(Error::NotEnoughShares);
|
||||
}
|
||||
|
||||
let public_attributes = voucher.get_public_attributes();
|
||||
let private_attributes = voucher.get_private_attributes();
|
||||
|
||||
let mut attributes = Vec::with_capacity(private_attributes.len() + public_attributes.len());
|
||||
attributes.extend_from_slice(&private_attributes);
|
||||
attributes.extend_from_slice(&public_attributes);
|
||||
@@ -150,8 +133,8 @@ pub fn prepare_credential_for_spending(
|
||||
params: &Parameters,
|
||||
voucher_value: u64,
|
||||
voucher_info: String,
|
||||
serial_number: Attribute,
|
||||
binding_number: Attribute,
|
||||
serial_number: &Attribute,
|
||||
binding_number: &Attribute,
|
||||
epoch_id: u64,
|
||||
signature: &Signature,
|
||||
verification_key: &VerificationKey,
|
||||
@@ -165,7 +148,7 @@ pub fn prepare_credential_for_spending(
|
||||
)?;
|
||||
|
||||
Ok(Credential::new(
|
||||
PUBLIC_ATTRIBUTES + PRIVATE_ATTRIBUTES,
|
||||
BandwidthVoucher::ENCODED_ATTRIBUTES,
|
||||
theta,
|
||||
voucher_value,
|
||||
voucher_info,
|
||||
|
||||
@@ -201,6 +201,17 @@ impl<'a> From<&'a PrivateKey> for PublicKey {
|
||||
}
|
||||
|
||||
impl PrivateKey {
|
||||
#[cfg(feature = "rand")]
|
||||
pub fn new<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
|
||||
let x25519_secret = x25519_dalek::StaticSecret::new(rng);
|
||||
|
||||
PrivateKey(x25519_secret)
|
||||
}
|
||||
|
||||
pub fn public_key(&self) -> PublicKey {
|
||||
self.into()
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> [u8; PRIVATE_KEY_SIZE] {
|
||||
self.0.to_bytes()
|
||||
}
|
||||
|
||||
@@ -5,13 +5,14 @@ pub use ed25519_dalek::ed25519::signature::Signature as SignatureTrait;
|
||||
pub use ed25519_dalek::SignatureError;
|
||||
pub use ed25519_dalek::{Verifier, PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, SIGNATURE_LENGTH};
|
||||
use nym_pemstore::traits::{PemStorableKey, PemStorableKeyPair};
|
||||
#[cfg(feature = "sphinx")]
|
||||
use nym_sphinx_types::{DestinationAddressBytes, DESTINATION_ADDRESS_LENGTH};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::str::FromStr;
|
||||
use thiserror::Error;
|
||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||
|
||||
#[cfg(feature = "sphinx")]
|
||||
use nym_sphinx_types::{DestinationAddressBytes, DESTINATION_ADDRESS_LENGTH};
|
||||
|
||||
#[cfg(feature = "rand")]
|
||||
use rand::{CryptoRng, RngCore};
|
||||
#[cfg(feature = "serde")]
|
||||
@@ -224,6 +225,17 @@ impl<'a> From<&'a PrivateKey> for PublicKey {
|
||||
}
|
||||
|
||||
impl PrivateKey {
|
||||
#[cfg(feature = "rand")]
|
||||
pub fn new<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
|
||||
let ed25519_secret = ed25519_dalek::SecretKey::generate(rng);
|
||||
|
||||
PrivateKey(ed25519_secret)
|
||||
}
|
||||
|
||||
pub fn public_key(&self) -> PublicKey {
|
||||
self.into()
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> [u8; SECRET_KEY_LENGTH] {
|
||||
self.0.to_bytes()
|
||||
}
|
||||
@@ -295,7 +307,7 @@ impl PemStorableKey for PrivateKey {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub struct Signature(ed25519_dalek::Signature);
|
||||
|
||||
impl Signature {
|
||||
@@ -319,6 +331,14 @@ impl Signature {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Signature {
|
||||
type Err = Ed25519RecoveryError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Signature::from_base58_string(s)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl Serialize for Signature {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
|
||||
@@ -3,6 +3,7 @@ name = "nym-dkg"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
resolver = "2"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -11,7 +12,7 @@ bitvec = "1.0.0"
|
||||
|
||||
# unfortunately until https://github.com/zkcrypto/bls12_381/issues/10 is resolved, we have to rely on the fork
|
||||
# as we need to be able to serialize Gt so that we could create the lookup table for baby-step-giant-step algorithm
|
||||
bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", branch ="gt-serialisation", default-features = false, features = ["alloc", "pairings", "experimental", "zeroize"] }
|
||||
bls12_381 = { workspace = true, default-features = false, features = ["alloc", "pairings", "experimental", "zeroize"] }
|
||||
nym-contracts-common = { path = "../cosmwasm-smart-contracts/contracts-common", optional = true }
|
||||
bs58 = "0.4"
|
||||
|
||||
@@ -29,11 +30,11 @@ zeroize = { workspace = true, features = ["zeroize_derive"] }
|
||||
nym-pemstore = { path = "../pemstore" }
|
||||
|
||||
[dependencies.group]
|
||||
version = "0.11"
|
||||
workspace = true
|
||||
default-features = false
|
||||
|
||||
[dependencies.ff]
|
||||
version = "0.11"
|
||||
workspace = true
|
||||
default-features = false
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
name = "nym-execute"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
name = "ledger"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -10,4 +11,4 @@ bip32 = "0.5.1"
|
||||
k256 = { workspace = true }
|
||||
ledger-transport = "0.10.0"
|
||||
ledger-transport-hid = "0.10.0"
|
||||
thiserror = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
@@ -3,6 +3,7 @@ name = "nym-mixnode-common"
|
||||
version = "0.1.0"
|
||||
authors = ["Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -20,7 +21,7 @@ tokio = { version = "1.24.1", features = [
|
||||
"net",
|
||||
"io-util",
|
||||
] }
|
||||
tokio-util = { version = "0.7.4", features = ["codec"] }
|
||||
tokio-util = { workspace = true, features = ["codec"] }
|
||||
url = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
|
||||
@@ -108,13 +108,13 @@ impl ConnectionHandler {
|
||||
let reply_packet = match maybe_echo_packet {
|
||||
Some(Ok(echo_packet)) => self.handle_echo_packet(echo_packet),
|
||||
Some(Err(err)) => {
|
||||
error!(
|
||||
debug!(
|
||||
"The socket connection got corrupted with error: {err}. Closing the socket",
|
||||
);
|
||||
return;
|
||||
}
|
||||
None => {
|
||||
error!("The socket connection got terminated by the remote!");
|
||||
debug!("The socket connection got terminated by the remote!");
|
||||
return;
|
||||
}
|
||||
};
|
||||
@@ -125,7 +125,7 @@ impl ConnectionHandler {
|
||||
.write_all(reply_packet.to_bytes().as_ref())
|
||||
.await
|
||||
{
|
||||
error!(
|
||||
debug!(
|
||||
"Failed to write reply packet back to the sender - {}. Closing the socket on our end",
|
||||
err
|
||||
);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
name = "nym-node-tester-utils"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ name = "nym-nonexhaustive-delayqueue"
|
||||
version = "0.1.0"
|
||||
authors = ["Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -3,11 +3,12 @@ name = "nym-coconut"
|
||||
version = "0.5.0"
|
||||
authors = ["Jedrzej Stuczynski <andrew@nymtech.net>", "Ania Piotrowska <ania@nymtech.net>"]
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", branch ="gt-serialisation", default-features = false, features = ["pairings", "alloc", "experimental"] }
|
||||
bls12_381 = { workspace = true, default-features = false, features = ["pairings", "alloc", "experimental"] }
|
||||
itertools = "0.10"
|
||||
digest = "0.9"
|
||||
rand = "0.8"
|
||||
@@ -16,16 +17,17 @@ serde = { workspace = true }
|
||||
serde_derive = "1.0"
|
||||
bs58 = "0.4.0"
|
||||
sha2 = "0.9"
|
||||
zeroize = { workspace = true, optional = true }
|
||||
|
||||
nym-dkg = { path = "../dkg" }
|
||||
nym-pemstore = { path = "../pemstore" }
|
||||
|
||||
[dependencies.ff]
|
||||
version = "0.11"
|
||||
workspace = true
|
||||
default-features = false
|
||||
|
||||
[dependencies.group]
|
||||
version = "0.11"
|
||||
workspace = true
|
||||
default-features = false
|
||||
|
||||
[dev-dependencies]
|
||||
@@ -38,7 +40,9 @@ name = "benchmarks"
|
||||
harness = false
|
||||
|
||||
[features]
|
||||
key-zeroize = ["zeroize", "bls12_381/zeroize"]
|
||||
default = []
|
||||
|
||||
|
||||
[target.'cfg(target_env = "wasm32-unknown-unknown")'.dependencies]
|
||||
getrandom = { version="0.2", features=["js"] }
|
||||
|
||||
@@ -7,7 +7,7 @@ use ff::Field;
|
||||
use group::{Curve, Group};
|
||||
use nym_coconut::{
|
||||
aggregate_signature_shares, aggregate_verification_keys, blind_sign, prepare_blind_sign,
|
||||
prove_bandwidth_credential, setup, ttp_keygen, verify_credential,
|
||||
prove_bandwidth_credential, random_scalars_refs, setup, ttp_keygen, verify_credential,
|
||||
verify_partial_blind_signature, Attribute, BlindedSignature, Parameters, Signature,
|
||||
SignatureShare, VerificationKey,
|
||||
};
|
||||
@@ -66,8 +66,8 @@ fn unblind_and_aggregate(
|
||||
params: &Parameters,
|
||||
blinded_signatures: &[BlindedSignature],
|
||||
partial_verification_keys: &[VerificationKey],
|
||||
private_attributes: &[Attribute],
|
||||
public_attributes: &[Attribute],
|
||||
private_attributes: &[&Attribute],
|
||||
public_attributes: &[&Attribute],
|
||||
commitment_hash: &G1Projective,
|
||||
pedersen_commitments_openings: &[Scalar],
|
||||
verification_key: &VerificationKey,
|
||||
@@ -78,7 +78,7 @@ fn unblind_and_aggregate(
|
||||
.zip(partial_verification_keys.iter())
|
||||
.map(|(signature, partial_verification_key)| {
|
||||
signature
|
||||
.unblind(
|
||||
.unblind_and_verify(
|
||||
params,
|
||||
partial_verification_key,
|
||||
private_attributes,
|
||||
@@ -171,10 +171,10 @@ fn bench_coconut(c: &mut Criterion) {
|
||||
|
||||
let params = setup(case.num_public_attrs + case.num_private_attrs).unwrap();
|
||||
|
||||
let public_attributes = params.n_random_scalars(case.num_public_attrs as usize);
|
||||
random_scalars_refs!(public_attributes, params, case.num_public_attrs as usize);
|
||||
let serial_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];
|
||||
|
||||
// The prepare blind sign is performed by the user
|
||||
let (pedersen_commitments_openings, blind_sign_request) =
|
||||
@@ -213,7 +213,7 @@ fn bench_coconut(c: &mut Criterion) {
|
||||
b.iter(|| {
|
||||
blind_sign(
|
||||
¶ms,
|
||||
&keypair.secret_key(),
|
||||
keypair.secret_key(),
|
||||
&blind_sign_request,
|
||||
&public_attributes,
|
||||
)
|
||||
@@ -228,7 +228,7 @@ fn bench_coconut(c: &mut Criterion) {
|
||||
for keypair in coconut_keypairs.iter() {
|
||||
let blinded_signature = blind_sign(
|
||||
¶ms,
|
||||
&keypair.secret_key(),
|
||||
keypair.secret_key(),
|
||||
&blind_sign_request,
|
||||
&public_attributes,
|
||||
)
|
||||
@@ -238,7 +238,7 @@ fn bench_coconut(c: &mut Criterion) {
|
||||
|
||||
let verification_keys: Vec<VerificationKey> = coconut_keypairs
|
||||
.iter()
|
||||
.map(|keypair| keypair.verification_key())
|
||||
.map(|keypair| keypair.verification_key().clone())
|
||||
.collect();
|
||||
|
||||
// verify a random partial blind signature
|
||||
@@ -310,8 +310,8 @@ fn bench_coconut(c: &mut Criterion) {
|
||||
¶ms,
|
||||
&aggr_verification_key,
|
||||
&aggregated_signature,
|
||||
serial_number,
|
||||
binding_number,
|
||||
&serial_number,
|
||||
&binding_number,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -329,8 +329,8 @@ fn bench_coconut(c: &mut Criterion) {
|
||||
¶ms,
|
||||
&aggr_verification_key,
|
||||
&aggregated_signature,
|
||||
serial_number,
|
||||
binding_number,
|
||||
&serial_number,
|
||||
&binding_number,
|
||||
)
|
||||
.unwrap()
|
||||
})
|
||||
|
||||
@@ -34,7 +34,10 @@ impl TryFrom<&[u8]> for Ciphertext {
|
||||
)));
|
||||
}
|
||||
|
||||
// safety: we just checked for the length so the unwraps are fine
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let c1_bytes: &[u8; 48] = &bytes[..48].try_into().unwrap();
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let c2_bytes: &[u8; 48] = &bytes[48..].try_into().unwrap();
|
||||
|
||||
let c1 = try_deserialize_g1_projective(
|
||||
@@ -112,7 +115,16 @@ impl Bytable for PrivateKey {
|
||||
}
|
||||
|
||||
fn try_from_byte_slice(slice: &[u8]) -> Result<Self> {
|
||||
PrivateKey::from_bytes(slice.try_into().unwrap())
|
||||
let received = slice.len();
|
||||
let Ok(arr) = slice.try_into() else {
|
||||
return Err(CoconutError::UnexpectedArrayLength {
|
||||
typ: "elgamal::PrivateKey".to_string(),
|
||||
received,
|
||||
expected: 32,
|
||||
});
|
||||
};
|
||||
|
||||
PrivateKey::from_bytes(arr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,21 +157,36 @@ impl PublicKey {
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> [u8; 48] {
|
||||
self.to_byte_vec().try_into().unwrap()
|
||||
self.0.to_affine().to_compressed()
|
||||
}
|
||||
|
||||
pub fn from_bytes(bytes: &[u8; 48]) -> Result<PublicKey> {
|
||||
Ok(PublicKey::try_from(bytes.to_vec().as_slice()).unwrap())
|
||||
try_deserialize_g1_projective(
|
||||
bytes,
|
||||
CoconutError::Deserialization(
|
||||
"Failed to deserialize compressed ElGamal public key".to_string(),
|
||||
),
|
||||
)
|
||||
.map(PublicKey)
|
||||
}
|
||||
}
|
||||
|
||||
impl Bytable for PublicKey {
|
||||
fn to_byte_vec(&self) -> Vec<u8> {
|
||||
self.0.to_affine().to_compressed().into()
|
||||
self.to_bytes().into()
|
||||
}
|
||||
|
||||
fn try_from_byte_slice(slice: &[u8]) -> Result<Self> {
|
||||
Ok(PublicKey::from_bytes(slice.try_into().unwrap()).unwrap())
|
||||
let received = slice.len();
|
||||
let Ok(arr) = slice.try_into() else {
|
||||
return Err(CoconutError::UnexpectedArrayLength {
|
||||
typ: "elgamal::PublicKey".to_string(),
|
||||
received,
|
||||
expected: 48,
|
||||
});
|
||||
};
|
||||
|
||||
PublicKey::from_bytes(arr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,13 +194,7 @@ impl TryFrom<&[u8]> for PublicKey {
|
||||
type Error = CoconutError;
|
||||
|
||||
fn try_from(slice: &[u8]) -> Result<PublicKey> {
|
||||
try_deserialize_g1_projective(
|
||||
slice.try_into().unwrap(),
|
||||
CoconutError::Deserialization(
|
||||
"Failed to deserialize compressed ElGamal public key".to_string(),
|
||||
),
|
||||
)
|
||||
.map(PublicKey)
|
||||
PublicKey::try_from_byte_slice(slice)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,7 +246,7 @@ pub fn elgamal_keygen(params: &Parameters) -> ElGamalKeyPair {
|
||||
|
||||
pub fn compute_attribute_encryption(
|
||||
params: &Parameters,
|
||||
private_attributes: &[Attribute],
|
||||
private_attributes: &[&Attribute],
|
||||
pub_key: &PublicKey,
|
||||
commitment_hash: G1Projective,
|
||||
) -> (Vec<Ciphertext>, Vec<EphemeralKey>) {
|
||||
|
||||
@@ -50,4 +50,20 @@ pub enum CoconutError {
|
||||
modulus: usize,
|
||||
object: String,
|
||||
},
|
||||
|
||||
#[error("received an array of unexpected size for deserialization of {typ}. got {received} but expected {expected}")]
|
||||
UnexpectedArrayLength {
|
||||
typ: String,
|
||||
received: usize,
|
||||
expected: usize,
|
||||
},
|
||||
|
||||
#[error("failed to decode the base58 representation: {0}")]
|
||||
Base58DecodingFailure(#[from] bs58::decode::Error),
|
||||
|
||||
#[error("failed to deserialize scalar from the received bytes - it might not have been canonically encoded")]
|
||||
ScalarDeserializationFailure,
|
||||
|
||||
#[error("failed to deserialize G1Projective point from the received bytes - it might not have been canonically encoded")]
|
||||
G1ProjectiveDeserializationFailure,
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::convert::TryInto;
|
||||
#![warn(clippy::expect_used)]
|
||||
#![warn(clippy::unwrap_used)]
|
||||
|
||||
use bls12_381::Scalar;
|
||||
|
||||
pub use crate::traits::Bytable;
|
||||
pub use elgamal::elgamal_keygen;
|
||||
pub use elgamal::ElGamalKeyPair;
|
||||
pub use elgamal::PublicKey;
|
||||
@@ -30,6 +28,7 @@ pub use scheme::BlindedSignature;
|
||||
pub use scheme::Signature;
|
||||
pub use scheme::SignatureShare;
|
||||
pub use traits::Base58;
|
||||
pub use traits::Bytable;
|
||||
pub use utils::hash_to_scalar;
|
||||
|
||||
pub mod elgamal;
|
||||
@@ -41,18 +40,6 @@ pub mod tests;
|
||||
mod traits;
|
||||
mod utils;
|
||||
|
||||
pub type Attribute = Scalar;
|
||||
pub type Attribute = bls12_381::Scalar;
|
||||
pub type PrivateAttribute = Attribute;
|
||||
pub type PublicAttribute = Attribute;
|
||||
|
||||
impl Bytable for Attribute {
|
||||
fn to_byte_vec(&self) -> Vec<u8> {
|
||||
self.to_bytes().to_vec()
|
||||
}
|
||||
|
||||
fn try_from_byte_slice(slice: &[u8]) -> Result<Self, CoconutError> {
|
||||
Ok(Attribute::from_bytes(slice.try_into().unwrap()).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl Base58 for Attribute {}
|
||||
|
||||
@@ -91,8 +91,8 @@ impl ProofCmCs {
|
||||
commitment_opening: &Scalar,
|
||||
commitments: &[G1Projective],
|
||||
pedersen_commitments_openings: &[Scalar],
|
||||
private_attributes: &[Attribute],
|
||||
public_attributes: &[Attribute],
|
||||
private_attributes: &[&Attribute],
|
||||
public_attributes: &[&Attribute],
|
||||
) -> Self {
|
||||
// note: this is only called from `prepare_blind_sign` that already checks
|
||||
// whether private attributes are non-empty and whether we don't have too many
|
||||
@@ -162,11 +162,8 @@ impl ProofCmCs {
|
||||
&challenge,
|
||||
&pedersen_commitments_openings.iter().collect::<Vec<_>>(),
|
||||
);
|
||||
let response_attributes = produce_responses(
|
||||
&witness_attributes,
|
||||
&challenge,
|
||||
&private_attributes.iter().collect::<Vec<_>>(),
|
||||
);
|
||||
let response_attributes =
|
||||
produce_responses(&witness_attributes, &challenge, private_attributes);
|
||||
|
||||
ProofCmCs {
|
||||
challenge,
|
||||
@@ -181,7 +178,7 @@ impl ProofCmCs {
|
||||
params: &Parameters,
|
||||
commitment: &G1Projective,
|
||||
commitments: &[G1Projective],
|
||||
public_attributes: &[Attribute],
|
||||
public_attributes: &[&Attribute],
|
||||
) -> bool {
|
||||
if self.response_attributes.len() != commitments.len() {
|
||||
return false;
|
||||
@@ -203,7 +200,7 @@ impl ProofCmCs {
|
||||
- public_attributes
|
||||
.iter()
|
||||
.zip(params.gen_hs().iter().skip(self.response_attributes.len()))
|
||||
.map(|(pub_attr, hs)| hs * pub_attr)
|
||||
.map(|(&pub_attr, hs)| hs * pub_attr)
|
||||
.sum::<G1Projective>())
|
||||
* self.challenge
|
||||
+ g1 * self.response_opening
|
||||
@@ -280,8 +277,12 @@ impl ProofCmCs {
|
||||
}
|
||||
|
||||
let mut idx = 0;
|
||||
// safety: bound checked + constant offset
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let challenge_bytes = bytes[idx..idx + 32].try_into().unwrap();
|
||||
idx += 32;
|
||||
// safety: bound checked + constant offset
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let response_opening_bytes = bytes[idx..idx + 32].try_into().unwrap();
|
||||
idx += 32;
|
||||
|
||||
@@ -297,6 +298,8 @@ impl ProofCmCs {
|
||||
),
|
||||
)?;
|
||||
|
||||
// safety: bound checked + constant offset
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let ro_len = u64::from_le_bytes(bytes[idx..idx + 8].try_into().unwrap());
|
||||
idx += 8;
|
||||
if bytes[idx..].len() < ro_len as usize * 32 + 8 {
|
||||
@@ -313,6 +316,8 @@ impl ProofCmCs {
|
||||
CoconutError::Deserialization("Failed to deserialize openings response".to_string()),
|
||||
)?;
|
||||
|
||||
// safety: bound checked + constant offset
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let rm_len = u64::from_le_bytes(bytes[ro_end..ro_end + 8].try_into().unwrap());
|
||||
let response_attributes = try_deserialize_scalar_vec(
|
||||
rm_len,
|
||||
@@ -462,7 +467,7 @@ impl ProofKappaZeta {
|
||||
|
||||
pub(crate) fn from_bytes(bytes: &[u8]) -> Result<Self> {
|
||||
// at the very minimum there must be a single attribute being proven
|
||||
if bytes.len() < 32 * 4 || (bytes.len()) % 32 != 0 {
|
||||
if bytes.len() != 128 {
|
||||
return Err(CoconutError::DeserializationInvalidLength {
|
||||
actual: bytes.len(),
|
||||
modulus_target: bytes.len(),
|
||||
@@ -472,24 +477,32 @@ impl ProofKappaZeta {
|
||||
});
|
||||
}
|
||||
|
||||
// safety: bound checked + constant offset
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let challenge_bytes = bytes[..32].try_into().unwrap();
|
||||
let challenge = try_deserialize_scalar(
|
||||
&challenge_bytes,
|
||||
CoconutError::Deserialization("Failed to deserialize challenge".to_string()),
|
||||
)?;
|
||||
|
||||
// safety: bound checked + constant offset
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let serial_number_bytes = &bytes[32..64].try_into().unwrap();
|
||||
let response_serial_number = try_deserialize_scalar(
|
||||
serial_number_bytes,
|
||||
CoconutError::Deserialization("failed to deserialize the serial number".to_string()),
|
||||
)?;
|
||||
|
||||
// safety: bound checked + constant offset
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let binding_number_bytes = &bytes[64..96].try_into().unwrap();
|
||||
let response_binding_number = try_deserialize_scalar(
|
||||
binding_number_bytes,
|
||||
CoconutError::Deserialization("failed to deserialize the binding number".to_string()),
|
||||
)?;
|
||||
|
||||
// safety: bound checked + constant offset
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let blinder_bytes = bytes[96..].try_into().unwrap();
|
||||
let response_blinder = try_deserialize_scalar(
|
||||
&blinder_bytes,
|
||||
@@ -512,14 +525,13 @@ impl ProofKappaZeta {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use group::Group;
|
||||
use rand::thread_rng;
|
||||
|
||||
use super::*;
|
||||
use crate::scheme::keygen::keygen;
|
||||
use crate::scheme::setup::setup;
|
||||
use crate::scheme::verification::{compute_kappa, compute_zeta};
|
||||
|
||||
use super::*;
|
||||
use crate::tests::helpers::random_scalars_refs;
|
||||
use group::Group;
|
||||
use rand::thread_rng;
|
||||
|
||||
#[test]
|
||||
fn proof_cm_cs_bytes_roundtrip() {
|
||||
@@ -530,7 +542,7 @@ mod tests {
|
||||
let r = params.random_scalar();
|
||||
let cms: [G1Projective; 1] = [G1Projective::random(&mut rng)];
|
||||
let rs = params.n_random_scalars(1);
|
||||
let private_attributes = params.n_random_scalars(1);
|
||||
random_scalars_refs!(private_attributes, params, 1);
|
||||
|
||||
// 0 public 1 private
|
||||
let pi_s = ProofCmCs::construct(¶ms, &cm, &r, &cms, &rs, &private_attributes, &[]);
|
||||
@@ -546,7 +558,7 @@ mod tests {
|
||||
G1Projective::random(&mut rng),
|
||||
];
|
||||
let rs = params.n_random_scalars(2);
|
||||
let private_attributes = params.n_random_scalars(2);
|
||||
random_scalars_refs!(private_attributes, params, 2);
|
||||
|
||||
// 0 public 2 privates
|
||||
let pi_s = ProofCmCs::construct(¶ms, &cm, &r, &cms, &rs, &private_attributes, &[]);
|
||||
@@ -562,20 +574,20 @@ mod tests {
|
||||
let keypair = keygen(¶ms);
|
||||
|
||||
// we don't care about 'correctness' of the proof. only whether we can correctly recover it from bytes
|
||||
let serial_number = params.random_scalar();
|
||||
let binding_number = params.random_scalar();
|
||||
let serial_number = ¶ms.random_scalar();
|
||||
let binding_number = ¶ms.random_scalar();
|
||||
let private_attributes = vec![serial_number, binding_number];
|
||||
|
||||
let r = params.random_scalar();
|
||||
let kappa = compute_kappa(¶ms, &keypair.verification_key(), &private_attributes, r);
|
||||
let kappa = compute_kappa(¶ms, keypair.verification_key(), &private_attributes, r);
|
||||
let zeta = compute_zeta(¶ms, serial_number);
|
||||
|
||||
// 0 public 2 private
|
||||
let pi_v = ProofKappaZeta::construct(
|
||||
¶ms,
|
||||
&keypair.verification_key(),
|
||||
&serial_number,
|
||||
&binding_number,
|
||||
keypair.verification_key(),
|
||||
serial_number,
|
||||
binding_number,
|
||||
&r,
|
||||
&kappa,
|
||||
&zeta,
|
||||
@@ -592,9 +604,9 @@ mod tests {
|
||||
|
||||
let pi_v = ProofKappaZeta::construct(
|
||||
¶ms,
|
||||
&keypair.verification_key(),
|
||||
&serial_number,
|
||||
&binding_number,
|
||||
keypair.verification_key(),
|
||||
serial_number,
|
||||
binding_number,
|
||||
&r,
|
||||
&kappa,
|
||||
&zeta,
|
||||
|
||||
@@ -83,7 +83,7 @@ pub fn aggregate_verification_keys(
|
||||
pub fn aggregate_signatures(
|
||||
params: &Parameters,
|
||||
verification_key: &VerificationKey,
|
||||
attributes: &[Attribute],
|
||||
attributes: &[&Attribute],
|
||||
signatures: &[PartialSignature],
|
||||
indices: Option<&[SignerIndex]>,
|
||||
) -> Result<Signature> {
|
||||
@@ -100,7 +100,7 @@ pub fn aggregate_signatures(
|
||||
let tmp = attributes
|
||||
.iter()
|
||||
.zip(verification_key.beta_g2.iter())
|
||||
.map(|(attr, beta_i)| beta_i * attr)
|
||||
.map(|(&attr, beta_i)| beta_i * attr)
|
||||
.sum::<G2Projective>();
|
||||
|
||||
if !check_bilinear_pairing(
|
||||
@@ -119,7 +119,7 @@ pub fn aggregate_signatures(
|
||||
pub fn aggregate_signature_shares(
|
||||
params: &Parameters,
|
||||
verification_key: &VerificationKey,
|
||||
attributes: &[Attribute],
|
||||
attributes: &[&Attribute],
|
||||
shares: &[SignatureShare],
|
||||
) -> Result<Signature> {
|
||||
let (signatures, indices): (Vec<_>, Vec<_>) = shares
|
||||
@@ -138,13 +138,13 @@ pub fn aggregate_signature_shares(
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use bls12_381::G1Projective;
|
||||
use group::Group;
|
||||
|
||||
use crate::scheme::issuance::sign;
|
||||
use crate::scheme::keygen::ttp_keygen;
|
||||
use crate::scheme::setup::Parameters;
|
||||
use crate::scheme::verification::verify;
|
||||
use crate::tests::helpers::random_scalars_refs;
|
||||
use bls12_381::G1Projective;
|
||||
use group::Group;
|
||||
|
||||
use super::*;
|
||||
|
||||
@@ -155,7 +155,7 @@ mod tests {
|
||||
|
||||
let vks = keypairs
|
||||
.into_iter()
|
||||
.map(|keypair| keypair.verification_key())
|
||||
.map(|keypair| keypair.verification_key().clone())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let aggr_vk1 = aggregate_verification_keys(&vks[..3], Some(&[1, 2, 3])).unwrap();
|
||||
@@ -212,13 +212,18 @@ mod tests {
|
||||
#[test]
|
||||
fn signature_aggregation_works_for_any_subset_of_signatures() {
|
||||
let mut params = Parameters::new(2).unwrap();
|
||||
let attributes = params.n_random_scalars(2);
|
||||
random_scalars_refs!(attributes, params, 2);
|
||||
|
||||
let keypairs = ttp_keygen(¶ms, 3, 5).unwrap();
|
||||
|
||||
let (sks, vks): (Vec<_>, Vec<_>) = keypairs
|
||||
.into_iter()
|
||||
.map(|keypair| (keypair.secret_key(), keypair.verification_key()))
|
||||
.map(|keypair| {
|
||||
(
|
||||
keypair.secret_key().clone(),
|
||||
keypair.verification_key().clone(),
|
||||
)
|
||||
})
|
||||
.unzip();
|
||||
|
||||
let sigs = sks
|
||||
@@ -312,12 +317,17 @@ mod tests {
|
||||
fn signature_aggregation_doesnt_work_for_empty_set_of_signatures() {
|
||||
let signatures: Vec<Signature> = vec![];
|
||||
let params = Parameters::new(2).unwrap();
|
||||
let attributes = params.n_random_scalars(2);
|
||||
random_scalars_refs!(attributes, params, 2);
|
||||
let keypairs = ttp_keygen(¶ms, 3, 5).unwrap();
|
||||
|
||||
let (_, vks): (Vec<_>, Vec<_>) = keypairs
|
||||
.into_iter()
|
||||
.map(|keypair| (keypair.secret_key(), keypair.verification_key()))
|
||||
.map(|keypair| {
|
||||
(
|
||||
keypair.secret_key().clone(),
|
||||
keypair.verification_key().clone(),
|
||||
)
|
||||
})
|
||||
.unzip();
|
||||
|
||||
let aggr_vk_all = aggregate_verification_keys(&vks, None).unwrap();
|
||||
@@ -330,11 +340,16 @@ mod tests {
|
||||
fn signature_aggregation_doesnt_work_if_indices_have_invalid_length() {
|
||||
let signatures = vec![random_signature()];
|
||||
let params = Parameters::new(2).unwrap();
|
||||
let attributes = params.n_random_scalars(2);
|
||||
random_scalars_refs!(attributes, params, 2);
|
||||
let keypairs = ttp_keygen(¶ms, 3, 5).unwrap();
|
||||
let (_, vks): (Vec<_>, Vec<_>) = keypairs
|
||||
.into_iter()
|
||||
.map(|keypair| (keypair.secret_key(), keypair.verification_key()))
|
||||
.map(|keypair| {
|
||||
(
|
||||
keypair.secret_key().clone(),
|
||||
keypair.verification_key().clone(),
|
||||
)
|
||||
})
|
||||
.unzip();
|
||||
let aggr_vk_all = aggregate_verification_keys(&vks, None).unwrap();
|
||||
|
||||
@@ -356,11 +371,16 @@ mod tests {
|
||||
fn signature_aggregation_doesnt_work_for_non_unique_indices() {
|
||||
let signatures = vec![random_signature(), random_signature()];
|
||||
let params = Parameters::new(2).unwrap();
|
||||
let attributes = params.n_random_scalars(2);
|
||||
random_scalars_refs!(attributes, params, 2);
|
||||
let keypairs = ttp_keygen(¶ms, 3, 5).unwrap();
|
||||
let (_, vks): (Vec<_>, Vec<_>) = keypairs
|
||||
.into_iter()
|
||||
.map(|keypair| (keypair.secret_key(), keypair.verification_key()))
|
||||
.map(|keypair| {
|
||||
(
|
||||
keypair.secret_key().clone(),
|
||||
keypair.verification_key().clone(),
|
||||
)
|
||||
})
|
||||
.unzip();
|
||||
let aggr_vk_all = aggregate_verification_keys(&vks, None).unwrap();
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@ impl TryFrom<&[u8]> for BlindedSerialNumber {
|
||||
));
|
||||
}
|
||||
|
||||
// safety: we've just made a check for 96 bytes
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let inner = try_deserialize_g2_projective(
|
||||
&bytes.try_into().unwrap(),
|
||||
CoconutError::Deserialization(
|
||||
|
||||
@@ -54,6 +54,8 @@ impl TryFrom<&[u8]> for BlindSignRequest {
|
||||
let commitment_bytes_len = 48;
|
||||
let commitment_hash_bytes_len = 48;
|
||||
|
||||
// safety: we made bound check and we're using constant offest
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let cm_bytes = bytes[..j + commitment_bytes_len].try_into().unwrap();
|
||||
let commitment = try_deserialize_g1_projective(
|
||||
&cm_bytes,
|
||||
@@ -63,6 +65,8 @@ impl TryFrom<&[u8]> for BlindSignRequest {
|
||||
)?;
|
||||
j += commitment_bytes_len;
|
||||
|
||||
// safety: we made bound check and we're using constant offest
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let cm_hash_bytes = bytes[j..j + commitment_hash_bytes_len].try_into().unwrap();
|
||||
let commitment_hash = try_deserialize_g1_projective(
|
||||
&cm_hash_bytes,
|
||||
@@ -72,6 +76,8 @@ impl TryFrom<&[u8]> for BlindSignRequest {
|
||||
)?;
|
||||
j += commitment_hash_bytes_len;
|
||||
|
||||
// safety: we made bound check and we're using constant offest
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let c_len = u64::from_le_bytes(bytes[j..j + 8].try_into().unwrap());
|
||||
j += 8;
|
||||
if bytes[j..].len() < c_len as usize * 48 {
|
||||
@@ -86,6 +92,14 @@ impl TryFrom<&[u8]> for BlindSignRequest {
|
||||
let start = j + i * 48;
|
||||
let end = start + 48;
|
||||
|
||||
if bytes.len() < end {
|
||||
return Err(CoconutError::Deserialization(
|
||||
"Failed to deserialize compressed commitment".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
// safety: we made bound check and we're using constant offest
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let private_attributes_commitment_bytes = bytes[start..end].try_into().unwrap();
|
||||
let private_attributes_commitment = try_deserialize_g1_projective(
|
||||
&private_attributes_commitment_bytes,
|
||||
@@ -137,7 +151,7 @@ impl Bytable for BlindSignRequest {
|
||||
impl Base58 for BlindSignRequest {}
|
||||
|
||||
impl BlindSignRequest {
|
||||
fn verify_proof(&self, params: &Parameters, public_attributes: &[Attribute]) -> bool {
|
||||
fn verify_proof(&self, params: &Parameters, public_attributes: &[&Attribute]) -> bool {
|
||||
self.pi_s.verify(
|
||||
params,
|
||||
&self.commitment,
|
||||
@@ -150,8 +164,8 @@ impl BlindSignRequest {
|
||||
self.commitment_hash
|
||||
}
|
||||
|
||||
pub fn get_private_attributes_pedersen_commitments(&self) -> Vec<G1Projective> {
|
||||
self.private_attributes_commitments.clone()
|
||||
pub fn get_private_attributes_pedersen_commitments(&self) -> &[G1Projective] {
|
||||
&self.private_attributes_commitments
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
@@ -161,12 +175,16 @@ impl BlindSignRequest {
|
||||
pub fn from_bytes(bytes: &[u8]) -> Result<BlindSignRequest> {
|
||||
BlindSignRequest::try_from(bytes)
|
||||
}
|
||||
|
||||
pub fn num_private_attributes(&self) -> usize {
|
||||
self.private_attributes_commitments.len()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compute_attributes_commitment(
|
||||
params: &Parameters,
|
||||
private_attributes: &[Attribute],
|
||||
public_attributes: &[Attribute],
|
||||
private_attributes: &[&Attribute],
|
||||
public_attributes: &[&Attribute],
|
||||
hs: &[G1Affine],
|
||||
) -> (Scalar, G1Projective) {
|
||||
let commitment_opening = params.random_scalar();
|
||||
@@ -187,7 +205,7 @@ pub fn compute_attributes_commitment(
|
||||
|
||||
pub fn compute_pedersen_commitments_for_private_attributes(
|
||||
params: &Parameters,
|
||||
private_attributes: &[Attribute],
|
||||
private_attributes: &[&Attribute],
|
||||
h: &G1Projective,
|
||||
) -> (Vec<Scalar>, Vec<G1Projective>) {
|
||||
// Generate openings for Pedersen commitment for each private attribute
|
||||
@@ -197,13 +215,13 @@ pub fn compute_pedersen_commitments_for_private_attributes(
|
||||
let pedersen_commitments = commitments_openings
|
||||
.iter()
|
||||
.zip(private_attributes.iter())
|
||||
.map(|(o_j, m_j)| params.gen1() * o_j + h * m_j)
|
||||
.map(|(o_j, &m_j)| params.gen1() * o_j + h * m_j)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
(commitments_openings, pedersen_commitments)
|
||||
}
|
||||
|
||||
pub fn compute_hash(commitment: G1Projective, public_attributes: &[Attribute]) -> G1Projective {
|
||||
pub fn compute_hash(commitment: G1Projective, public_attributes: &[&Attribute]) -> G1Projective {
|
||||
let mut buff = Vec::new();
|
||||
buff.extend_from_slice(commitment.to_bytes().as_ref());
|
||||
for attr in public_attributes {
|
||||
@@ -215,8 +233,8 @@ pub fn compute_hash(commitment: G1Projective, public_attributes: &[Attribute]) -
|
||||
/// Builds cryptographic material required for blind sign.
|
||||
pub fn prepare_blind_sign(
|
||||
params: &Parameters,
|
||||
private_attributes: &[Attribute],
|
||||
public_attributes: &[Attribute],
|
||||
private_attributes: &[&Attribute],
|
||||
public_attributes: &[&Attribute],
|
||||
) -> Result<(Vec<Scalar>, BlindSignRequest)> {
|
||||
if private_attributes.is_empty() {
|
||||
return Err(CoconutError::Issuance(
|
||||
@@ -271,7 +289,7 @@ pub fn blind_sign(
|
||||
params: &Parameters,
|
||||
signing_secret_key: &SecretKey,
|
||||
blind_sign_request: &BlindSignRequest,
|
||||
public_attributes: &[Attribute],
|
||||
public_attributes: &[&Attribute],
|
||||
) -> Result<BlindedSignature> {
|
||||
let num_private = blind_sign_request.private_attributes_commitments.len();
|
||||
let hs = params.gen_hs();
|
||||
@@ -304,7 +322,7 @@ pub fn blind_sign(
|
||||
let signed_public = h * public_attributes
|
||||
.iter()
|
||||
.zip(signing_secret_key.ys.iter().skip(num_private))
|
||||
.map(|(attr, yi)| attr * yi)
|
||||
.map(|(&attr, yi)| attr * yi)
|
||||
.sum::<Scalar>();
|
||||
|
||||
// h ^ x + c[0] ^ y[0] + ... c[m] ^ y[m] + h ^ (pub_m[0] * y[m + 1] + ... + pub_m[n] * y[m + n])
|
||||
@@ -345,7 +363,7 @@ pub fn blind_sign(
|
||||
pub fn verify_partial_blind_signature(
|
||||
params: &Parameters,
|
||||
blind_sign_request: &BlindSignRequest,
|
||||
public_attributes: &[Attribute],
|
||||
public_attributes: &[&Attribute],
|
||||
blind_sig: &BlindedSignature,
|
||||
partial_verification_key: &VerificationKey,
|
||||
) -> bool {
|
||||
@@ -383,7 +401,7 @@ pub fn verify_partial_blind_signature(
|
||||
}
|
||||
|
||||
// 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(
|
||||
for (&pub_attr, beta_g2) in public_attributes.iter().zip(
|
||||
partial_verification_key
|
||||
.beta_g2
|
||||
.iter()
|
||||
@@ -415,7 +433,7 @@ pub fn verify_partial_blind_signature(
|
||||
pub fn sign(
|
||||
params: &mut Parameters,
|
||||
secret_key: &SecretKey,
|
||||
public_attributes: &[Attribute],
|
||||
public_attributes: &[&Attribute],
|
||||
) -> Result<Signature> {
|
||||
if public_attributes.len() > secret_key.ys.len() {
|
||||
return Err(CoconutError::IssuanceMaxAttributes {
|
||||
@@ -429,7 +447,7 @@ pub fn sign(
|
||||
// (the python implementation hashes string representation of all attributes onto the curve,
|
||||
// but I think the same can be achieved by just summing the attributes thus avoiding the unnecessary
|
||||
// transformation. If I'm wrong, please correct me.)
|
||||
let attributes_sum = public_attributes.iter().sum::<Scalar>();
|
||||
let attributes_sum = public_attributes.iter().copied().sum::<Scalar>();
|
||||
let h = hash_g1((params.gen1() * attributes_sum).to_bytes());
|
||||
|
||||
// x + m0 * y0 + m1 * y1 + ... mn * yn
|
||||
@@ -437,7 +455,7 @@ pub fn sign(
|
||||
+ public_attributes
|
||||
.iter()
|
||||
.zip(secret_key.ys.iter())
|
||||
.map(|(m_i, y_i)| m_i * y_i)
|
||||
.map(|(&m_i, y_i)| m_i * y_i)
|
||||
.sum::<Scalar>();
|
||||
|
||||
let sig2 = h * exponent;
|
||||
@@ -448,13 +466,14 @@ pub fn sign(
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::scheme::keygen::keygen;
|
||||
use crate::tests::helpers::random_scalars_refs;
|
||||
|
||||
#[test]
|
||||
fn blind_sign_request_bytes_roundtrip() {
|
||||
// 0 public and 1 private attribute
|
||||
let params = Parameters::new(1).unwrap();
|
||||
let private_attributes = params.n_random_scalars(1);
|
||||
let public_attributes = params.n_random_scalars(0);
|
||||
random_scalars_refs!(private_attributes, params, 1);
|
||||
random_scalars_refs!(public_attributes, params, 0);
|
||||
|
||||
let (_commitments_openings, lambda) =
|
||||
prepare_blind_sign(¶ms, &private_attributes, &public_attributes).unwrap();
|
||||
@@ -467,8 +486,8 @@ mod tests {
|
||||
|
||||
// 2 public and 2 private attributes
|
||||
let params = Parameters::new(4).unwrap();
|
||||
let private_attributes = params.n_random_scalars(2);
|
||||
let public_attributes = params.n_random_scalars(2);
|
||||
random_scalars_refs!(private_attributes, params, 2);
|
||||
random_scalars_refs!(public_attributes, params, 2);
|
||||
|
||||
let (_commitments_openings, lambda) =
|
||||
prepare_blind_sign(¶ms, &private_attributes, &public_attributes).unwrap();
|
||||
@@ -483,8 +502,8 @@ mod tests {
|
||||
#[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);
|
||||
random_scalars_refs!(private_attributes, params, 2);
|
||||
random_scalars_refs!(public_attributes, params, 2);
|
||||
|
||||
let (_commitments_openings, request) =
|
||||
prepare_blind_sign(¶ms, &private_attributes, &public_attributes).unwrap();
|
||||
@@ -492,7 +511,7 @@ mod tests {
|
||||
let validator_keypair = keygen(¶ms);
|
||||
let blind_sig = blind_sign(
|
||||
¶ms,
|
||||
&validator_keypair.secret_key(),
|
||||
validator_keypair.secret_key(),
|
||||
&request,
|
||||
&public_attributes,
|
||||
)
|
||||
@@ -503,36 +522,35 @@ mod tests {
|
||||
&request,
|
||||
&public_attributes,
|
||||
&blind_sig,
|
||||
&validator_keypair.verification_key()
|
||||
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);
|
||||
random_scalars_refs!(private_attributes, params, 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();
|
||||
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()
|
||||
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);
|
||||
random_scalars_refs!(private_attributes, params, 2);
|
||||
random_scalars_refs!(public_attributes, params, 2);
|
||||
|
||||
let (_commitments_openings, request) =
|
||||
prepare_blind_sign(¶ms, &private_attributes, &public_attributes).unwrap();
|
||||
@@ -541,7 +559,7 @@ mod tests {
|
||||
let validator2_keypair = keygen(¶ms);
|
||||
let blind_sig = blind_sign(
|
||||
¶ms,
|
||||
&validator_keypair.secret_key(),
|
||||
validator_keypair.secret_key(),
|
||||
&request,
|
||||
&public_attributes,
|
||||
)
|
||||
@@ -553,7 +571,7 @@ mod tests {
|
||||
&request,
|
||||
&public_attributes,
|
||||
&blind_sig,
|
||||
&validator2_keypair.verification_key()
|
||||
validator2_keypair.verification_key()
|
||||
),);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +23,12 @@ use crate::utils::{
|
||||
};
|
||||
use crate::Base58;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(PartialEq, Eq))]
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(test, derive(PartialEq, Eq, Clone))]
|
||||
#[cfg_attr(
|
||||
feature = "key-zeroize",
|
||||
derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop)
|
||||
)]
|
||||
pub struct SecretKey {
|
||||
pub(crate) x: Scalar,
|
||||
pub(crate) ys: Vec<Scalar>,
|
||||
@@ -62,7 +66,9 @@ impl TryFrom<&[u8]> for SecretKey {
|
||||
}
|
||||
|
||||
// this conversion will not fail as we are taking the same length of data
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let x_bytes: [u8; 32] = bytes[..32].try_into().unwrap();
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let ys_len = u64::from_le_bytes(bytes[32..40].try_into().unwrap());
|
||||
let actual_ys_len = (bytes.len() - 40) / 32;
|
||||
|
||||
@@ -97,6 +103,10 @@ impl SecretKey {
|
||||
(self.x, self.ys.clone())
|
||||
}
|
||||
|
||||
pub fn size(&self) -> usize {
|
||||
self.ys.len()
|
||||
}
|
||||
|
||||
/// Derive verification key using this secret key.
|
||||
pub fn verification_key(&self, params: &Parameters) -> VerificationKey {
|
||||
let g1 = params.gen1();
|
||||
@@ -141,6 +151,10 @@ impl Base58 for SecretKey {}
|
||||
// TODO: perhaps change points to affine representation
|
||||
// to make verification slightly more efficient?
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
#[cfg_attr(
|
||||
feature = "key-zeroize",
|
||||
derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop)
|
||||
)]
|
||||
pub struct VerificationKey {
|
||||
// TODO add gen2 as per the paper or imply it from the fact library is using bls381?
|
||||
pub(crate) alpha: G2Projective,
|
||||
@@ -180,7 +194,9 @@ impl TryFrom<&[u8]> for VerificationKey {
|
||||
}
|
||||
|
||||
// this conversion will not fail as we are taking the same length of data
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let alpha_bytes: [u8; 96] = bytes[..96].try_into().unwrap();
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let betas_len = u64::from_le_bytes(bytes[96..104].try_into().unwrap());
|
||||
|
||||
let actual_betas_len = (bytes.len() - 104) / (96 + 48);
|
||||
@@ -204,6 +220,8 @@ impl TryFrom<&[u8]> for VerificationKey {
|
||||
for i in 0..betas_len {
|
||||
let start = (104 + i * 48) as usize;
|
||||
let end = start + 48;
|
||||
// we're using a constant 48 byte offset (which is the size of G1 compressed) so unwrap is fine
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let beta_i_bytes = bytes[start..end].try_into().unwrap();
|
||||
let beta_i = try_deserialize_g1_projective(
|
||||
&beta_i_bytes,
|
||||
@@ -220,6 +238,8 @@ impl TryFrom<&[u8]> for VerificationKey {
|
||||
for i in 0..betas_len {
|
||||
let start = (beta_g1_end + i * 96) as usize;
|
||||
let end = start + 96;
|
||||
// we're using a constant 96 byte offset (which is the size of G2 compressed) so unwrap is fine
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let beta_i_bytes = bytes[start..end].try_into().unwrap();
|
||||
let beta_i = try_deserialize_g2_projective(
|
||||
&beta_i_bytes,
|
||||
@@ -392,7 +412,11 @@ impl Bytable for VerificationKey {
|
||||
impl Base58 for VerificationKey {}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[cfg_attr(test, derive(PartialEq, Eq))]
|
||||
#[cfg_attr(test, derive(PartialEq, Eq, Clone))]
|
||||
#[cfg_attr(
|
||||
feature = "key-zeroize",
|
||||
derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop)
|
||||
)]
|
||||
pub struct KeyPair {
|
||||
secret_key: SecretKey,
|
||||
verification_key: VerificationKey,
|
||||
@@ -429,12 +453,12 @@ impl KeyPair {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn secret_key(&self) -> SecretKey {
|
||||
self.secret_key.clone()
|
||||
pub fn secret_key(&self) -> &SecretKey {
|
||||
&self.secret_key
|
||||
}
|
||||
|
||||
pub fn verification_key(&self) -> VerificationKey {
|
||||
self.verification_key.clone()
|
||||
pub fn verification_key(&self) -> &VerificationKey {
|
||||
&self.verification_key
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
@@ -488,6 +512,8 @@ impl TryFrom<&[u8]> for KeyPair {
|
||||
});
|
||||
}
|
||||
|
||||
// safety: we made bound check and we're using constant offest
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let secret_key_len =
|
||||
u64::from_le_bytes(bytes[header_len..header_len + 8].try_into().unwrap()) as usize;
|
||||
let secret_key_start = header_len + 8;
|
||||
@@ -503,6 +529,8 @@ impl TryFrom<&[u8]> for KeyPair {
|
||||
});
|
||||
}
|
||||
|
||||
// safety: we made bound check
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let verification_key_len = u64::from_le_bytes(
|
||||
bytes[secret_key_start + secret_key_len..secret_key_start + secret_key_len + 8]
|
||||
.try_into()
|
||||
@@ -515,6 +543,7 @@ impl TryFrom<&[u8]> for KeyPair {
|
||||
)?;
|
||||
let consumed_bytes = verification_key_start + verification_key_len;
|
||||
let index = if consumed_bytes < bytes.len() && [consumed_bytes..].len() == 8 {
|
||||
#[allow(clippy::unwrap_used)]
|
||||
Some(u64::from_le_bytes(
|
||||
bytes[consumed_bytes..consumed_bytes + 8]
|
||||
.try_into()
|
||||
|
||||
@@ -44,7 +44,10 @@ impl TryFrom<&[u8]> for Signature {
|
||||
)));
|
||||
}
|
||||
|
||||
// safety: we just checked for the length so the unwraps are fine
|
||||
#[allow(clippy::expect_used)]
|
||||
let sig1_bytes: &[u8; 48] = &bytes[..48].try_into().expect("Slice size != 48");
|
||||
#[allow(clippy::expect_used)]
|
||||
let sig2_bytes: &[u8; 48] = &bytes[48..].try_into().expect("Slice size != 48");
|
||||
|
||||
let sig1 = try_deserialize_g1_projective(
|
||||
@@ -88,6 +91,45 @@ impl Signature {
|
||||
pub fn from_bytes(bytes: &[u8]) -> Result<Signature> {
|
||||
Signature::try_from(bytes)
|
||||
}
|
||||
|
||||
pub fn verify(
|
||||
&self,
|
||||
params: &Parameters,
|
||||
partial_verification_key: &VerificationKey,
|
||||
private_attributes: &[&Attribute],
|
||||
public_attributes: &[&Attribute],
|
||||
commitment_hash: &G1Projective,
|
||||
) -> Result<()> {
|
||||
// Verify the commitment hash
|
||||
if !(commitment_hash == &self.0) {
|
||||
return Err(CoconutError::Verification(
|
||||
"Verification of commitment hash from signature failed".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let alpha = partial_verification_key.alpha;
|
||||
|
||||
let signed_attributes = private_attributes
|
||||
.iter()
|
||||
.chain(public_attributes.iter())
|
||||
.zip(partial_verification_key.beta_g2.iter())
|
||||
.map(|(&attr, beta_i)| beta_i * attr)
|
||||
.sum::<G2Projective>();
|
||||
|
||||
// Verify the signature share
|
||||
if !check_bilinear_pairing(
|
||||
&self.0.to_affine(),
|
||||
&G2Prepared::from((alpha + signed_attributes).to_affine()),
|
||||
&self.1.to_affine(),
|
||||
params.prepared_miller_g2(),
|
||||
) {
|
||||
return Err(CoconutError::Unblind(
|
||||
"Verification of signature share failed".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Bytable for Signature {
|
||||
@@ -102,8 +144,7 @@ impl Bytable for Signature {
|
||||
|
||||
impl Base58 for Signature {}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(test, derive(PartialEq, Eq))]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct BlindedSignature(G1Projective, G1Projective);
|
||||
|
||||
impl Bytable for BlindedSignature {
|
||||
@@ -129,7 +170,10 @@ impl TryFrom<&[u8]> for BlindedSignature {
|
||||
)));
|
||||
}
|
||||
|
||||
// safety: we just checked for the length so the unwraps are fine
|
||||
#[allow(clippy::expect_used)]
|
||||
let h_bytes: &[u8; 48] = &bytes[..48].try_into().expect("Slice size != 48");
|
||||
#[allow(clippy::expect_used)]
|
||||
let sig_bytes: &[u8; 48] = &bytes[48..].try_into().expect("Slice size != 48");
|
||||
|
||||
let h = try_deserialize_g1_projective(
|
||||
@@ -148,24 +192,12 @@ impl TryFrom<&[u8]> for BlindedSignature {
|
||||
impl BlindedSignature {
|
||||
pub fn unblind(
|
||||
&self,
|
||||
params: &Parameters,
|
||||
partial_verification_key: &VerificationKey,
|
||||
private_attributes: &[Attribute],
|
||||
public_attributes: &[Attribute],
|
||||
commitment_hash: &G1Projective,
|
||||
pedersen_commitments_openings: &[Scalar],
|
||||
) -> Result<Signature> {
|
||||
// parse the signature
|
||||
let h = &self.0;
|
||||
let c = &self.1;
|
||||
|
||||
// Verify the commitment hash
|
||||
if !(commitment_hash == h) {
|
||||
return Err(CoconutError::Unblind(
|
||||
"Verification of commitment hash from signature failed".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let blinding_removers = partial_verification_key
|
||||
.beta_g1
|
||||
.iter()
|
||||
@@ -175,30 +207,29 @@ impl BlindedSignature {
|
||||
|
||||
let unblinded_c = c - blinding_removers;
|
||||
|
||||
let alpha = partial_verification_key.alpha;
|
||||
|
||||
let signed_attributes = private_attributes
|
||||
.iter()
|
||||
.chain(public_attributes.iter())
|
||||
.zip(partial_verification_key.beta_g2.iter())
|
||||
.map(|(attr, beta_i)| beta_i * attr)
|
||||
.sum::<G2Projective>();
|
||||
|
||||
// Verify the signature share
|
||||
if !check_bilinear_pairing(
|
||||
&h.to_affine(),
|
||||
&G2Prepared::from((alpha + signed_attributes).to_affine()),
|
||||
&unblinded_c.to_affine(),
|
||||
params.prepared_miller_g2(),
|
||||
) {
|
||||
return Err(CoconutError::Unblind(
|
||||
"Verification of signature share failed".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(Signature(*h, unblinded_c))
|
||||
}
|
||||
|
||||
pub fn unblind_and_verify(
|
||||
&self,
|
||||
params: &Parameters,
|
||||
partial_verification_key: &VerificationKey,
|
||||
private_attributes: &[&Attribute],
|
||||
public_attributes: &[&Attribute],
|
||||
commitment_hash: &G1Projective,
|
||||
pedersen_commitments_openings: &[Scalar],
|
||||
) -> Result<Signature> {
|
||||
let unblinded = self.unblind(partial_verification_key, pedersen_commitments_openings)?;
|
||||
unblinded.verify(
|
||||
params,
|
||||
partial_verification_key,
|
||||
private_attributes,
|
||||
public_attributes,
|
||||
commitment_hash,
|
||||
)?;
|
||||
Ok(unblinded)
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> [u8; 96] {
|
||||
let mut bytes = [0u8; 96];
|
||||
bytes[..48].copy_from_slice(&self.0.to_affine().to_compressed());
|
||||
@@ -237,25 +268,25 @@ impl SignatureShare {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::hash_to_scalar;
|
||||
use crate::scheme::aggregation::{aggregate_signatures, aggregate_verification_keys};
|
||||
use crate::scheme::issuance::{blind_sign, compute_hash, prepare_blind_sign, sign};
|
||||
use crate::scheme::keygen::{keygen, ttp_keygen};
|
||||
use crate::scheme::verification::{prove_bandwidth_credential, verify, verify_credential};
|
||||
|
||||
use super::*;
|
||||
use crate::tests::helpers::random_scalars_refs;
|
||||
|
||||
#[test]
|
||||
fn unblind_returns_error_if_integrity_check_on_commitment_hash_fails() {
|
||||
let params = Parameters::new(2).unwrap();
|
||||
let private_attributes = params.n_random_scalars(2_usize);
|
||||
random_scalars_refs!(private_attributes, params, 2);
|
||||
|
||||
let (_commitments_openings, lambda) =
|
||||
prepare_blind_sign(¶ms, &private_attributes, &[]).unwrap();
|
||||
|
||||
let keypair1 = keygen(¶ms);
|
||||
|
||||
let sig1 = blind_sign(¶ms, &keypair1.secret_key(), &lambda, &[]).unwrap();
|
||||
let sig1 = blind_sign(¶ms, keypair1.secret_key(), &lambda, &[]).unwrap();
|
||||
|
||||
let wrong_commitment_opening = params.random_scalar();
|
||||
let wrong_commitment = params.gen1() * wrong_commitment_opening;
|
||||
@@ -263,9 +294,9 @@ mod tests {
|
||||
let wrong_commitments_openings = params.n_random_scalars(private_attributes.len());
|
||||
|
||||
assert!(sig1
|
||||
.unblind(
|
||||
.unblind_and_verify(
|
||||
¶ms,
|
||||
&keypair1.verification_key(),
|
||||
keypair1.verification_key(),
|
||||
&private_attributes,
|
||||
&[],
|
||||
&fake_commitment_hash,
|
||||
@@ -277,20 +308,23 @@ mod tests {
|
||||
#[test]
|
||||
fn unblind_returns_error_if_signature_verification_fails() {
|
||||
let params = Parameters::new(2).unwrap();
|
||||
let private_attributes = vec![hash_to_scalar("Attribute1"), hash_to_scalar("Attribute2")];
|
||||
let private_attributes2 = vec![hash_to_scalar("Attribute3"), hash_to_scalar("Attribute4")];
|
||||
let p = [hash_to_scalar("Attribute1"), hash_to_scalar("Attribute2")];
|
||||
let private_attributes = vec![&p[0], &p[1]];
|
||||
|
||||
let p2 = [hash_to_scalar("Attribute3"), hash_to_scalar("Attribute4")];
|
||||
let private_attributes2 = vec![&p2[0], &p2[1]];
|
||||
|
||||
let (commitments_openings, lambda) =
|
||||
prepare_blind_sign(¶ms, &private_attributes, &[]).unwrap();
|
||||
|
||||
let keypair1 = keygen(¶ms);
|
||||
|
||||
let sig1 = blind_sign(¶ms, &keypair1.secret_key(), &lambda, &[]).unwrap();
|
||||
let sig1 = blind_sign(¶ms, keypair1.secret_key(), &lambda, &[]).unwrap();
|
||||
|
||||
assert!(sig1
|
||||
.unblind(
|
||||
.unblind_and_verify(
|
||||
¶ms,
|
||||
&keypair1.verification_key(),
|
||||
keypair1.verification_key(),
|
||||
&private_attributes2,
|
||||
&[],
|
||||
&lambda.get_commitment_hash(),
|
||||
@@ -304,7 +338,7 @@ mod tests {
|
||||
let params = Parameters::new(2).unwrap();
|
||||
let serial_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 keypair1 = keygen(¶ms);
|
||||
let keypair2 = keygen(¶ms);
|
||||
@@ -312,11 +346,11 @@ mod tests {
|
||||
let (commitments_openings, lambda) =
|
||||
prepare_blind_sign(¶ms, &private_attributes, &[]).unwrap();
|
||||
|
||||
let sig1 = blind_sign(¶ms, &keypair1.secret_key(), &lambda, &[])
|
||||
let sig1 = blind_sign(¶ms, keypair1.secret_key(), &lambda, &[])
|
||||
.unwrap()
|
||||
.unblind(
|
||||
.unblind_and_verify(
|
||||
¶ms,
|
||||
&keypair1.verification_key(),
|
||||
keypair1.verification_key(),
|
||||
&private_attributes,
|
||||
&[],
|
||||
&lambda.get_commitment_hash(),
|
||||
@@ -324,11 +358,11 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let sig2 = blind_sign(¶ms, &keypair2.secret_key(), &lambda, &[])
|
||||
let sig2 = blind_sign(¶ms, keypair2.secret_key(), &lambda, &[])
|
||||
.unwrap()
|
||||
.unblind(
|
||||
.unblind_and_verify(
|
||||
¶ms,
|
||||
&keypair2.verification_key(),
|
||||
keypair2.verification_key(),
|
||||
&private_attributes,
|
||||
&[],
|
||||
&lambda.get_commitment_hash(),
|
||||
@@ -338,39 +372,39 @@ mod tests {
|
||||
|
||||
let theta1 = prove_bandwidth_credential(
|
||||
¶ms,
|
||||
&keypair1.verification_key(),
|
||||
keypair1.verification_key(),
|
||||
&sig1,
|
||||
serial_number,
|
||||
binding_number,
|
||||
&serial_number,
|
||||
&binding_number,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let theta2 = prove_bandwidth_credential(
|
||||
¶ms,
|
||||
&keypair2.verification_key(),
|
||||
keypair2.verification_key(),
|
||||
&sig2,
|
||||
serial_number,
|
||||
binding_number,
|
||||
&serial_number,
|
||||
&binding_number,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert!(verify_credential(
|
||||
¶ms,
|
||||
&keypair1.verification_key(),
|
||||
keypair1.verification_key(),
|
||||
&theta1,
|
||||
&[],
|
||||
));
|
||||
|
||||
assert!(verify_credential(
|
||||
¶ms,
|
||||
&keypair2.verification_key(),
|
||||
keypair2.verification_key(),
|
||||
&theta2,
|
||||
&[],
|
||||
));
|
||||
|
||||
assert!(!verify_credential(
|
||||
¶ms,
|
||||
&keypair1.verification_key(),
|
||||
keypair1.verification_key(),
|
||||
&theta2,
|
||||
&[],
|
||||
));
|
||||
@@ -379,30 +413,30 @@ mod tests {
|
||||
#[test]
|
||||
fn verification_on_two_public_attributes() {
|
||||
let mut params = Parameters::new(2).unwrap();
|
||||
let attributes = params.n_random_scalars(2);
|
||||
random_scalars_refs!(attributes, params, 2);
|
||||
|
||||
let keypair1 = keygen(¶ms);
|
||||
let keypair2 = keygen(¶ms);
|
||||
let sig1 = sign(&mut params, &keypair1.secret_key(), &attributes).unwrap();
|
||||
let sig2 = sign(&mut params, &keypair2.secret_key(), &attributes).unwrap();
|
||||
let sig1 = sign(&mut params, keypair1.secret_key(), &attributes).unwrap();
|
||||
let sig2 = sign(&mut params, keypair2.secret_key(), &attributes).unwrap();
|
||||
|
||||
assert!(verify(
|
||||
¶ms,
|
||||
&keypair1.verification_key(),
|
||||
keypair1.verification_key(),
|
||||
&attributes,
|
||||
&sig1,
|
||||
));
|
||||
|
||||
assert!(!verify(
|
||||
¶ms,
|
||||
&keypair2.verification_key(),
|
||||
keypair2.verification_key(),
|
||||
&attributes,
|
||||
&sig1,
|
||||
));
|
||||
|
||||
assert!(!verify(
|
||||
¶ms,
|
||||
&keypair1.verification_key(),
|
||||
keypair1.verification_key(),
|
||||
&attributes,
|
||||
&sig2,
|
||||
));
|
||||
@@ -411,10 +445,11 @@ mod tests {
|
||||
#[test]
|
||||
fn verification_on_two_public_and_two_private_attributes() {
|
||||
let params = Parameters::new(4).unwrap();
|
||||
let public_attributes = params.n_random_scalars(2);
|
||||
random_scalars_refs!(public_attributes, params, 2);
|
||||
|
||||
let serial_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 keypair1 = keygen(¶ms);
|
||||
let keypair2 = keygen(¶ms);
|
||||
@@ -422,11 +457,11 @@ mod tests {
|
||||
let (commitments_openings, lambda) =
|
||||
prepare_blind_sign(¶ms, &private_attributes, &public_attributes).unwrap();
|
||||
|
||||
let sig1 = blind_sign(¶ms, &keypair1.secret_key(), &lambda, &public_attributes)
|
||||
let sig1 = blind_sign(¶ms, keypair1.secret_key(), &lambda, &public_attributes)
|
||||
.unwrap()
|
||||
.unblind(
|
||||
.unblind_and_verify(
|
||||
¶ms,
|
||||
&keypair1.verification_key(),
|
||||
keypair1.verification_key(),
|
||||
&private_attributes,
|
||||
&public_attributes,
|
||||
&lambda.get_commitment_hash(),
|
||||
@@ -434,11 +469,11 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let sig2 = blind_sign(¶ms, &keypair2.secret_key(), &lambda, &public_attributes)
|
||||
let sig2 = blind_sign(¶ms, keypair2.secret_key(), &lambda, &public_attributes)
|
||||
.unwrap()
|
||||
.unblind(
|
||||
.unblind_and_verify(
|
||||
¶ms,
|
||||
&keypair2.verification_key(),
|
||||
keypair2.verification_key(),
|
||||
&private_attributes,
|
||||
&public_attributes,
|
||||
&lambda.get_commitment_hash(),
|
||||
@@ -448,39 +483,39 @@ mod tests {
|
||||
|
||||
let theta1 = prove_bandwidth_credential(
|
||||
¶ms,
|
||||
&keypair1.verification_key(),
|
||||
keypair1.verification_key(),
|
||||
&sig1,
|
||||
serial_number,
|
||||
binding_number,
|
||||
&serial_number,
|
||||
&binding_number,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let theta2 = prove_bandwidth_credential(
|
||||
¶ms,
|
||||
&keypair2.verification_key(),
|
||||
keypair2.verification_key(),
|
||||
&sig2,
|
||||
serial_number,
|
||||
binding_number,
|
||||
&serial_number,
|
||||
&binding_number,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert!(verify_credential(
|
||||
¶ms,
|
||||
&keypair1.verification_key(),
|
||||
keypair1.verification_key(),
|
||||
&theta1,
|
||||
&public_attributes,
|
||||
));
|
||||
|
||||
assert!(verify_credential(
|
||||
¶ms,
|
||||
&keypair2.verification_key(),
|
||||
keypair2.verification_key(),
|
||||
&theta2,
|
||||
&public_attributes,
|
||||
));
|
||||
|
||||
assert!(!verify_credential(
|
||||
¶ms,
|
||||
&keypair1.verification_key(),
|
||||
keypair1.verification_key(),
|
||||
&theta2,
|
||||
&public_attributes,
|
||||
));
|
||||
@@ -489,10 +524,11 @@ mod tests {
|
||||
#[test]
|
||||
fn verification_on_two_public_and_two_private_attributes_from_two_signers() {
|
||||
let params = Parameters::new(4).unwrap();
|
||||
let public_attributes = params.n_random_scalars(2);
|
||||
random_scalars_refs!(public_attributes, params, 2);
|
||||
|
||||
let serial_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 keypairs = ttp_keygen(¶ms, 2, 3).unwrap();
|
||||
|
||||
@@ -502,11 +538,11 @@ mod tests {
|
||||
let sigs = keypairs
|
||||
.iter()
|
||||
.map(|keypair| {
|
||||
blind_sign(¶ms, &keypair.secret_key(), &lambda, &public_attributes)
|
||||
blind_sign(¶ms, keypair.secret_key(), &lambda, &public_attributes)
|
||||
.unwrap()
|
||||
.unblind(
|
||||
.unblind_and_verify(
|
||||
¶ms,
|
||||
&keypair.verification_key(),
|
||||
keypair.verification_key(),
|
||||
&private_attributes,
|
||||
&public_attributes,
|
||||
&lambda.get_commitment_hash(),
|
||||
@@ -518,7 +554,7 @@ mod tests {
|
||||
|
||||
let vks = keypairs
|
||||
.into_iter()
|
||||
.map(|keypair| keypair.verification_key())
|
||||
.map(|keypair| keypair.verification_key().clone())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut attributes = Vec::with_capacity(private_attributes.len() + public_attributes.len());
|
||||
@@ -530,9 +566,14 @@ mod tests {
|
||||
aggregate_signatures(¶ms, &aggr_vk, &attributes, &sigs[..2], Some(&[1, 2]))
|
||||
.unwrap();
|
||||
|
||||
let theta =
|
||||
prove_bandwidth_credential(¶ms, &aggr_vk, &aggr_sig, serial_number, binding_number)
|
||||
.unwrap();
|
||||
let theta = prove_bandwidth_credential(
|
||||
¶ms,
|
||||
&aggr_vk,
|
||||
&aggr_sig,
|
||||
&serial_number,
|
||||
&binding_number,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert!(verify_credential(
|
||||
¶ms,
|
||||
@@ -547,9 +588,14 @@ mod tests {
|
||||
aggregate_signatures(¶ms, &aggr_vk, &attributes, &sigs[1..], Some(&[2, 3]))
|
||||
.unwrap();
|
||||
|
||||
let theta =
|
||||
prove_bandwidth_credential(¶ms, &aggr_vk, &aggr_sig, serial_number, binding_number)
|
||||
.unwrap();
|
||||
let theta = prove_bandwidth_credential(
|
||||
¶ms,
|
||||
&aggr_vk,
|
||||
&aggr_sig,
|
||||
&serial_number,
|
||||
&binding_number,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert!(verify_credential(
|
||||
¶ms,
|
||||
|
||||
@@ -43,6 +43,8 @@ impl TryFrom<&[u8]> for Theta {
|
||||
));
|
||||
}
|
||||
|
||||
// safety: we just checked for the length so the unwraps are fine
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let blinded_message_bytes = bytes[..96].try_into().unwrap();
|
||||
let blinded_message = try_deserialize_g2_projective(
|
||||
&blinded_message_bytes,
|
||||
@@ -51,6 +53,8 @@ impl TryFrom<&[u8]> for Theta {
|
||||
),
|
||||
)?;
|
||||
|
||||
// safety: we just checked for the length so the unwraps are fine
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let blinded_serial_number_bytes = bytes[96..192].try_into().unwrap();
|
||||
let blinded_serial_number = try_deserialize_g2_projective(
|
||||
&blinded_serial_number_bytes,
|
||||
@@ -130,7 +134,7 @@ impl Base58 for Theta {}
|
||||
pub fn compute_kappa(
|
||||
params: &Parameters,
|
||||
verification_key: &VerificationKey,
|
||||
private_attributes: &[Attribute],
|
||||
private_attributes: &[&Attribute],
|
||||
blinding_factor: Scalar,
|
||||
) -> G2Projective {
|
||||
params.gen2() * blinding_factor
|
||||
@@ -138,11 +142,11 @@ pub fn compute_kappa(
|
||||
+ private_attributes
|
||||
.iter()
|
||||
.zip(verification_key.beta_g2.iter())
|
||||
.map(|(priv_attr, beta_i)| beta_i * priv_attr)
|
||||
.map(|(&priv_attr, beta_i)| beta_i * priv_attr)
|
||||
.sum::<G2Projective>()
|
||||
}
|
||||
|
||||
pub fn compute_zeta(params: &Parameters, serial_number: Attribute) -> G2Projective {
|
||||
pub fn compute_zeta(params: &Parameters, serial_number: &Attribute) -> G2Projective {
|
||||
params.gen2() * serial_number
|
||||
}
|
||||
|
||||
@@ -150,8 +154,8 @@ pub fn prove_bandwidth_credential(
|
||||
params: &Parameters,
|
||||
verification_key: &VerificationKey,
|
||||
signature: &Signature,
|
||||
serial_number: Attribute,
|
||||
binding_number: Attribute,
|
||||
serial_number: &Attribute,
|
||||
binding_number: &Attribute,
|
||||
) -> Result<Theta> {
|
||||
if verification_key.beta_g2.len() < 2 {
|
||||
return Err(
|
||||
@@ -171,7 +175,7 @@ pub fn prove_bandwidth_credential(
|
||||
// Thus, we need kappa which allows us to verify sigma'. In particular,
|
||||
// kappa is computed on m as input, but thanks to the use or random value r,
|
||||
// it does not reveal any information about m.
|
||||
let private_attributes = vec![serial_number, binding_number];
|
||||
let private_attributes = [serial_number, binding_number];
|
||||
let blinded_message = compute_kappa(
|
||||
params,
|
||||
verification_key,
|
||||
@@ -185,8 +189,8 @@ pub fn prove_bandwidth_credential(
|
||||
let pi_v = ProofKappaZeta::construct(
|
||||
params,
|
||||
verification_key,
|
||||
&serial_number,
|
||||
&binding_number,
|
||||
serial_number,
|
||||
binding_number,
|
||||
&sign_blinding_factor,
|
||||
&blinded_message,
|
||||
&blinded_serial_number,
|
||||
@@ -221,7 +225,10 @@ pub fn check_vk_pairing(
|
||||
if values_len == 0 || values_len - 1 != vk.beta_g1.len() || values_len - 1 != vk.beta_g2.len() {
|
||||
return false;
|
||||
}
|
||||
if vk.alpha != *dkg_values.last().unwrap() {
|
||||
|
||||
// safety: we made an explicit check for if the length of the slice is 0, thus unwrap here is fine
|
||||
#[allow(clippy::unwrap_used)]
|
||||
if &vk.alpha != *dkg_values.last().as_ref().unwrap() {
|
||||
return false;
|
||||
}
|
||||
if dkg_values
|
||||
@@ -249,7 +256,7 @@ pub fn verify_credential(
|
||||
params: &Parameters,
|
||||
verification_key: &VerificationKey,
|
||||
theta: &Theta,
|
||||
public_attributes: &[Attribute],
|
||||
public_attributes: &[&Attribute],
|
||||
) -> bool {
|
||||
if public_attributes.len() + theta.pi_v.private_attributes_len()
|
||||
> verification_key.beta_g2.len()
|
||||
@@ -272,7 +279,7 @@ pub fn verify_credential(
|
||||
.iter()
|
||||
.skip(theta.pi_v.private_attributes_len()),
|
||||
)
|
||||
.map(|(pub_attr, beta_i)| beta_i * pub_attr)
|
||||
.map(|(&pub_attr, beta_i)| beta_i * pub_attr)
|
||||
.sum::<G2Projective>();
|
||||
|
||||
theta.blinded_message + signed_public_attributes
|
||||
@@ -291,14 +298,14 @@ pub fn verify_credential(
|
||||
pub fn verify(
|
||||
params: &Parameters,
|
||||
verification_key: &VerificationKey,
|
||||
public_attributes: &[Attribute],
|
||||
public_attributes: &[&Attribute],
|
||||
sig: &Signature,
|
||||
) -> bool {
|
||||
let kappa = (verification_key.alpha
|
||||
+ public_attributes
|
||||
.iter()
|
||||
.zip(verification_key.beta_g2.iter())
|
||||
.map(|(m_i, b_i)| b_i * m_i)
|
||||
.map(|(&m_i, b_i)| b_i * m_i)
|
||||
.sum::<G2Projective>())
|
||||
.to_affine();
|
||||
|
||||
@@ -320,10 +327,11 @@ mod tests {
|
||||
#[test]
|
||||
fn vk_pairing() {
|
||||
let params = setup(2).unwrap();
|
||||
let vk = keygen(¶ms).verification_key();
|
||||
let keypair = keygen(¶ms);
|
||||
let vk = keypair.verification_key();
|
||||
let mut dkg_values = vk.beta_g2.clone();
|
||||
dkg_values.push(vk.alpha);
|
||||
assert!(check_vk_pairing(¶ms, &dkg_values, &vk));
|
||||
assert!(check_vk_pairing(¶ms, &dkg_values, vk));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -340,10 +348,10 @@ mod tests {
|
||||
|
||||
let theta = prove_bandwidth_credential(
|
||||
¶ms,
|
||||
&keypair.verification_key(),
|
||||
keypair.verification_key(),
|
||||
&signature,
|
||||
serial_number,
|
||||
binding_number,
|
||||
&serial_number,
|
||||
&binding_number,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::random_scalars_refs;
|
||||
use crate::tests::helpers::tests::generate_dkg_keys;
|
||||
use crate::{
|
||||
aggregate_verification_keys, setup, tests::helpers::*, ttp_keygen, verify_credential,
|
||||
@@ -12,14 +13,14 @@ fn keygen() -> Result<(), CoconutError> {
|
||||
let params = setup(5)?;
|
||||
let node_indices = vec![15u64, 248, 33521];
|
||||
|
||||
let public_attributes = params.n_random_scalars(2);
|
||||
random_scalars_refs!(public_attributes, params, 2);
|
||||
|
||||
// generate_keys
|
||||
let coconut_keypairs = ttp_keygen(¶ms, 2, 3)?;
|
||||
|
||||
let verification_keys: Vec<VerificationKey> = coconut_keypairs
|
||||
.iter()
|
||||
.map(|keypair| keypair.verification_key())
|
||||
.map(|keypair| keypair.verification_key().clone())
|
||||
.collect();
|
||||
|
||||
// aggregate verification keys
|
||||
@@ -50,14 +51,14 @@ fn dkg() -> Result<(), CoconutError> {
|
||||
let params = setup(5)?;
|
||||
let node_indices = vec![15u64, 248, 33521];
|
||||
|
||||
let public_attributes = params.n_random_scalars(2);
|
||||
random_scalars_refs!(public_attributes, params, 2);
|
||||
|
||||
// generate_keys
|
||||
let coconut_keypairs = generate_dkg_keys(5, &node_indices);
|
||||
|
||||
let verification_keys: Vec<VerificationKey> = coconut_keypairs
|
||||
.iter()
|
||||
.map(|keypair| keypair.verification_key())
|
||||
.map(|keypair| keypair.verification_key().clone())
|
||||
.collect();
|
||||
|
||||
// aggregate verification keys
|
||||
|
||||
@@ -5,15 +5,17 @@ use crate::*;
|
||||
use itertools::izip;
|
||||
use std::fmt::Debug;
|
||||
|
||||
// unwraps are fine in the test code
|
||||
#[allow(clippy::unwrap_used)]
|
||||
pub fn theta_from_keys_and_attributes(
|
||||
params: &Parameters,
|
||||
coconut_keypairs: &Vec<KeyPair>,
|
||||
indices: &[scheme::SignerIndex],
|
||||
public_attributes: &Vec<PublicAttribute>,
|
||||
public_attributes: &[&PublicAttribute],
|
||||
) -> Result<Theta, CoconutError> {
|
||||
let serial_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];
|
||||
|
||||
// generate commitment
|
||||
let (commitments_openings, blind_sign_request) =
|
||||
@@ -21,7 +23,7 @@ pub fn theta_from_keys_and_attributes(
|
||||
|
||||
let verification_keys: Vec<VerificationKey> = coconut_keypairs
|
||||
.iter()
|
||||
.map(|keypair| keypair.verification_key())
|
||||
.map(|keypair| keypair.verification_key().clone())
|
||||
.collect();
|
||||
|
||||
// aggregate verification keys
|
||||
@@ -33,7 +35,7 @@ pub fn theta_from_keys_and_attributes(
|
||||
for keypair in coconut_keypairs {
|
||||
let blinded_signature = blind_sign(
|
||||
params,
|
||||
&keypair.secret_key(),
|
||||
keypair.secret_key(),
|
||||
&blind_sign_request,
|
||||
public_attributes,
|
||||
)?;
|
||||
@@ -49,7 +51,7 @@ pub fn theta_from_keys_and_attributes(
|
||||
.map(|(idx, s, vk)| {
|
||||
(
|
||||
*idx,
|
||||
s.unblind(
|
||||
s.unblind_and_verify(
|
||||
params,
|
||||
vk,
|
||||
&private_attributes,
|
||||
@@ -81,13 +83,15 @@ pub fn theta_from_keys_and_attributes(
|
||||
params,
|
||||
&verification_key,
|
||||
&signature,
|
||||
serial_number,
|
||||
binding_number,
|
||||
&serial_number,
|
||||
&binding_number,
|
||||
)?;
|
||||
|
||||
Ok(theta)
|
||||
}
|
||||
|
||||
// unwraps are fine in the test code
|
||||
#[allow(clippy::unwrap_used)]
|
||||
pub fn transpose_matrix<T: Debug>(matrix: Vec<Vec<T>>) -> Vec<Vec<T>> {
|
||||
if matrix.is_empty() {
|
||||
return vec![];
|
||||
@@ -166,3 +170,14 @@ pub mod tests {
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! random_scalars_refs {
|
||||
( $x: ident, $params: expr, $n: expr ) => {
|
||||
let _vec = $params.n_random_scalars($n);
|
||||
#[allow(clippy::map_identity)]
|
||||
let $x = _vec.iter().collect::<Vec<_>>();
|
||||
};
|
||||
}
|
||||
|
||||
pub use random_scalars_refs;
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#![warn(clippy::expect_used)]
|
||||
#![warn(clippy::unwrap_used)]
|
||||
|
||||
use crate::CoconutError;
|
||||
use bls12_381::{G1Affine, G1Projective, Scalar};
|
||||
use group::GroupEncoding;
|
||||
use std::convert::TryInto;
|
||||
|
||||
pub trait Bytable
|
||||
where
|
||||
@@ -14,9 +23,67 @@ where
|
||||
Self: Bytable,
|
||||
{
|
||||
fn try_from_bs58<S: AsRef<str>>(x: S) -> Result<Self, CoconutError> {
|
||||
Self::try_from_byte_slice(&bs58::decode(x.as_ref()).into_vec().unwrap())
|
||||
let bs58_decoded = &bs58::decode(x.as_ref()).into_vec()?;
|
||||
Self::try_from_byte_slice(bs58_decoded)
|
||||
}
|
||||
fn to_bs58(&self) -> String {
|
||||
bs58::encode(self.to_byte_vec()).into_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl Bytable for Scalar {
|
||||
fn to_byte_vec(&self) -> Vec<u8> {
|
||||
self.to_bytes().to_vec()
|
||||
}
|
||||
|
||||
fn try_from_byte_slice(slice: &[u8]) -> Result<Self, CoconutError> {
|
||||
let received = slice.len();
|
||||
let Ok(arr) = slice.try_into() else {
|
||||
return Err(CoconutError::UnexpectedArrayLength {
|
||||
typ: "Scalar".to_string(),
|
||||
received,
|
||||
expected: 32,
|
||||
});
|
||||
};
|
||||
|
||||
let maybe_scalar = Scalar::from_bytes(arr);
|
||||
if maybe_scalar.is_none().into() {
|
||||
Err(CoconutError::ScalarDeserializationFailure)
|
||||
} else {
|
||||
// safety: this unwrap is fine as we've just checked the element is not none
|
||||
#[allow(clippy::unwrap_used)]
|
||||
Ok(maybe_scalar.unwrap())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Base58 for Scalar {}
|
||||
|
||||
impl Bytable for G1Projective {
|
||||
fn to_byte_vec(&self) -> Vec<u8> {
|
||||
self.to_bytes().as_ref().to_vec()
|
||||
}
|
||||
|
||||
fn try_from_byte_slice(slice: &[u8]) -> Result<Self, CoconutError> {
|
||||
let received = slice.len();
|
||||
let arr: Result<[u8; 48], _> = slice.try_into();
|
||||
let Ok(bytes) = arr else {
|
||||
return Err(CoconutError::UnexpectedArrayLength {
|
||||
typ: "G1Projective".to_string(),
|
||||
received,
|
||||
expected: 48,
|
||||
});
|
||||
};
|
||||
|
||||
let maybe_g1 = G1Affine::from_compressed(&bytes);
|
||||
if maybe_g1.is_none().into() {
|
||||
Err(CoconutError::G1ProjectiveDeserializationFailure)
|
||||
} else {
|
||||
// safety: this unwrap is fine as we've just checked the element is not none
|
||||
#[allow(clippy::unwrap_used)]
|
||||
Ok(maybe_g1.unwrap().into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Base58 for G1Projective {}
|
||||
|
||||
@@ -34,6 +34,7 @@ impl Polynomial {
|
||||
// just return the last term of the polynomial
|
||||
} else if x.is_zero().into() {
|
||||
// we checked that coefficients are not empty so unwrap here is fine
|
||||
#[allow(clippy::unwrap_used)]
|
||||
*self.coefficients.first().unwrap()
|
||||
} else {
|
||||
self.coefficients
|
||||
@@ -148,6 +149,8 @@ pub(crate) fn try_deserialize_scalar_vec(
|
||||
|
||||
let mut out = Vec::with_capacity(expected_len as usize);
|
||||
for i in 0..expected_len as usize {
|
||||
// we just checked we have exactly the amount of bytes we need and thus the unwrap is fine
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let s_bytes = bytes[i * 32..(i + 1) * 32].try_into().unwrap();
|
||||
let s = match Into::<Option<Scalar>>::into(Scalar::from_bytes(&s_bytes)) {
|
||||
None => return Err(err),
|
||||
|
||||
@@ -9,7 +9,7 @@ repository = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
bytes = "1.0"
|
||||
tokio-util = { version = "0.7.4", features = ["codec"] }
|
||||
tokio-util = { workspace = true, features = ["codec"] }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
nym-sphinx-types = { path = "../types", features = ["sphinx", "outfox"] }
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
name = "nym-socks5-client-core"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ name = "nym-ordered-buffer"
|
||||
version = "0.1.0"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -3,13 +3,14 @@ name = "nym-socks5-proxy-helpers"
|
||||
version = "0.1.0"
|
||||
authors = ["Jedrzej Stuczynski <andrew@nymtech.net>"]
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
bytes = "1.0"
|
||||
tokio = { version = "1.24.1", features = [ "net", "io-util", "sync", "macros", "time", "rt-multi-thread" ] }
|
||||
tokio-util = { version = "0.7.4", features = [ "io" ] } # reason for getting this guy is to to able to port to tokio 1.X more quickly by being able to use
|
||||
tokio = { workspace = true, features = [ "net", "io-util", "sync", "macros", "time", "rt-multi-thread" ] }
|
||||
tokio-util = { workspace = true, features = [ "io" ] } # reason for getting this guy is to to able to port to tokio 1.X more quickly by being able to use
|
||||
# their `read_buf` [from the util crate] replacement rather than having to rethink/reimplement `AvailableReader` with the new AsyncRead trait definition.
|
||||
# In the long run, the dependency should probably get removed in favour of pure-tokio implementation, but for time being it's fine.
|
||||
futures = { workspace = true }
|
||||
|
||||
@@ -3,6 +3,7 @@ name = "nym-socks5-requests"
|
||||
version = "0.1.0"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
name = "nym-statistics-common"
|
||||
version = "1.0.1"
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
name = "nym-store-cipher"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -20,4 +21,4 @@ getrandom = { version = "0.2", features = ["js"] }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
json = ["serde_json"]
|
||||
json = ["serde_json"]
|
||||
|
||||
@@ -495,11 +495,14 @@ impl Drop for TaskClient {
|
||||
if !self.mode.should_signal_on_drop() {
|
||||
self.log(
|
||||
Level::Trace,
|
||||
"the task client is getting dropped (but instructed to not signal)",
|
||||
"the task client is getting dropped but inststructed to not signal: this is expected during client shutdown",
|
||||
);
|
||||
return;
|
||||
} else {
|
||||
self.log(Level::Debug, "the task client is getting dropped");
|
||||
self.log(
|
||||
Level::Debug,
|
||||
"the task client is getting dropped: this is expected during client shutdown",
|
||||
);
|
||||
}
|
||||
|
||||
if !self.is_shutdown_poll() {
|
||||
|
||||
@@ -5,6 +5,7 @@ description = "Nym common types"
|
||||
authors.workspace = true
|
||||
edition = "2021"
|
||||
rust-version = "1.58"
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
base64 = "0.21.4"
|
||||
|
||||
@@ -77,7 +77,7 @@ impl GatewayBond {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct GatewayNodeDetailsResponse {
|
||||
pub identity_key: String,
|
||||
pub sphinx_key: String,
|
||||
@@ -88,6 +88,7 @@ pub struct GatewayNodeDetailsResponse {
|
||||
pub data_store: String,
|
||||
|
||||
pub network_requester: Option<GatewayNetworkRequesterDetails>,
|
||||
pub ip_packet_router: Option<GatewayIpPacketRouterDetails>,
|
||||
}
|
||||
|
||||
impl fmt::Display for GatewayNodeDetailsResponse {
|
||||
@@ -98,7 +99,7 @@ impl fmt::Display for GatewayNodeDetailsResponse {
|
||||
writeln!(f, "bind address: {}", self.bind_address)?;
|
||||
writeln!(
|
||||
f,
|
||||
"mix Port: {}, clients port: {}",
|
||||
"mix port: {}, clients port: {}",
|
||||
self.mix_port, self.clients_port
|
||||
)?;
|
||||
|
||||
@@ -107,11 +108,15 @@ impl fmt::Display for GatewayNodeDetailsResponse {
|
||||
if let Some(nr) = &self.network_requester {
|
||||
nr.fmt(f)?;
|
||||
}
|
||||
|
||||
if let Some(ipr) = &self.ip_packet_router {
|
||||
ipr.fmt(f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct GatewayNetworkRequesterDetails {
|
||||
pub enabled: bool,
|
||||
|
||||
@@ -149,7 +154,7 @@ impl fmt::Display for GatewayNetworkRequesterDetails {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct GatewayIpPacketRouterDetails {
|
||||
pub enabled: bool,
|
||||
|
||||
@@ -164,7 +169,7 @@ pub struct GatewayIpPacketRouterDetails {
|
||||
|
||||
impl fmt::Display for GatewayIpPacketRouterDetails {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
writeln!(f, "IP packet router:")?;
|
||||
writeln!(f, "ip packet router:")?;
|
||||
writeln!(f, "\tenabled: {}", self.enabled)?;
|
||||
writeln!(f, "\tconfig path: {}", self.config_path)?;
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ name = "wasm-storage"
|
||||
version = "0.1.0"
|
||||
authors = ["Jedrzej Stuczynski <andrew@nymtech.net>"]
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -17,4 +18,4 @@ indexed_db_futures = { version = " 0.3.0"}
|
||||
thiserror = { workspace = true }
|
||||
|
||||
nym-store-cipher = { path = "../../store-cipher", features = ["json"] }
|
||||
wasm-utils = { path = "../utils", default-features = false }
|
||||
wasm-utils = { path = "../utils", default-features = false }
|
||||
|
||||
@@ -3,6 +3,7 @@ name = "wasm-utils"
|
||||
version = "0.1.0"
|
||||
authors = ["Jedrzej Stuczynski <andrew@nymtech.net>"]
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -22,4 +22,5 @@ log.workspace = true
|
||||
nym-network-defaults = { path = "../network-defaults" }
|
||||
nym-task = { path = "../task" }
|
||||
nym-wireguard-types = { path = "../wireguard-types" }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
tokio = { workspace = true, features = ["rt-multi-thread", "net", "io-util"] }
|
||||
|
||||
+10
-11
@@ -9,13 +9,12 @@ use nym_wireguard_types::registration::GatewayClientRegistry;
|
||||
use std::sync::Arc;
|
||||
|
||||
// Currently the module related to setting up the virtual network device is platform specific.
|
||||
use crate::setup::PeerPair;
|
||||
#[cfg(target_os = "linux")]
|
||||
use crate::setup::{peer_allowed_ips, peer_static_public_key, PRIVATE_KEY};
|
||||
use crate::setup::{peer_static_pairs, PRIVATE_KEY};
|
||||
use defguard_wireguard_rs::WGApi;
|
||||
#[cfg(target_os = "linux")]
|
||||
use defguard_wireguard_rs::{
|
||||
host::Peer, key::Key, net::IpAddrMask, InterfaceConfiguration, WireguardInterfaceApi,
|
||||
};
|
||||
use defguard_wireguard_rs::{InterfaceConfiguration, WireguardInterfaceApi};
|
||||
#[cfg(target_os = "linux")]
|
||||
use nym_network_defaults::{WG_PORT, WG_TUN_DEVICE_ADDRESS};
|
||||
|
||||
@@ -24,6 +23,7 @@ use nym_network_defaults::{WG_PORT, WG_TUN_DEVICE_ADDRESS};
|
||||
pub async fn start_wireguard(
|
||||
mut task_client: nym_task::TaskClient,
|
||||
_gateway_client_registry: Arc<GatewayClientRegistry>,
|
||||
peer_pairs: Vec<PeerPair>,
|
||||
) -> Result<WGApi, Box<dyn std::error::Error + Send + Sync + 'static>> {
|
||||
let ifname = String::from("wg0");
|
||||
let wgapi = WGApi::new(ifname.clone(), false)?;
|
||||
@@ -36,13 +36,11 @@ pub async fn start_wireguard(
|
||||
peers: vec![],
|
||||
};
|
||||
wgapi.configure_interface(&interface_config)?;
|
||||
let peer = peer_static_public_key();
|
||||
let mut peer = Peer::new(Key::new(peer.to_bytes()));
|
||||
let peer_ip = peer_allowed_ips();
|
||||
let peer_ip_mask = IpAddrMask::new(peer_ip.network_address(), peer_ip.netmask());
|
||||
peer.set_allowed_ips(vec![peer_ip_mask]);
|
||||
wgapi.configure_peer(&peer)?;
|
||||
wgapi.configure_peer_routing(&[peer.clone()])?;
|
||||
let peers = peer_static_pairs(peer_pairs);
|
||||
for peer in peers.iter() {
|
||||
wgapi.configure_peer(peer)?;
|
||||
}
|
||||
wgapi.configure_peer_routing(&peers)?;
|
||||
|
||||
tokio::spawn(async move { task_client.recv().await });
|
||||
|
||||
@@ -52,6 +50,7 @@ pub async fn start_wireguard(
|
||||
pub async fn start_wireguard(
|
||||
_task_client: nym_task::TaskClient,
|
||||
_gateway_client_registry: Arc<GatewayClientRegistry>,
|
||||
_peer_pairs: Vec<PeerPair>,
|
||||
) -> Result<WGApi, Box<dyn std::error::Error + Send + Sync + 'static>> {
|
||||
todo!("WireGuard is currently only supported on Linux")
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
use std::net::IpAddr;
|
||||
|
||||
use base64::{engine::general_purpose, Engine as _};
|
||||
use log::info;
|
||||
use defguard_wireguard_rs::host::Peer;
|
||||
use defguard_wireguard_rs::key::Key;
|
||||
use defguard_wireguard_rs::net::IpAddrMask;
|
||||
use log::{info, warn};
|
||||
use serde::Deserialize;
|
||||
|
||||
// The wireguard UDP listener
|
||||
pub const WG_ADDRESS: &str = "0.0.0.0";
|
||||
@@ -10,21 +14,23 @@ pub const WG_ADDRESS: &str = "0.0.0.0";
|
||||
// Corresponding public key: "WM8s8bYegwMa0TJ+xIwhk+dImk2IpDUKslDBCZPizlE="
|
||||
pub(crate) const PRIVATE_KEY: &str = "AEqXrLFT4qjYq3wmX0456iv94uM6nDj5ugp6Jedcflg=";
|
||||
|
||||
// The AllowedIPs for the connected peer, which is one a single IP and the same as the IP that the
|
||||
// peer has configured on their side.
|
||||
const ALLOWED_IPS: &str = "10.1.0.2";
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct PeerPair {
|
||||
pub addr: String,
|
||||
pub public_key: String,
|
||||
}
|
||||
|
||||
fn decode_base64_key(base64_key: &str) -> [u8; 32] {
|
||||
fn decode_base64_key(base64_key: &str) -> Result<[u8; 32], String> {
|
||||
general_purpose::STANDARD
|
||||
.decode(base64_key)
|
||||
.unwrap()
|
||||
.map_err(|_| String::from("Could not decode"))?
|
||||
.try_into()
|
||||
.unwrap()
|
||||
.map_err(|_| String::from("Not enough bytes"))
|
||||
}
|
||||
|
||||
pub fn server_static_private_key() -> x25519_dalek::StaticSecret {
|
||||
// TODO: this is a temporary solution for development
|
||||
let static_private_bytes: [u8; 32] = decode_base64_key(PRIVATE_KEY);
|
||||
let static_private_bytes: [u8; 32] = decode_base64_key(PRIVATE_KEY).unwrap();
|
||||
let static_private = x25519_dalek::StaticSecret::from(static_private_bytes);
|
||||
let static_public = x25519_dalek::PublicKey::from(&static_private);
|
||||
info!(
|
||||
@@ -34,23 +40,29 @@ pub fn server_static_private_key() -> x25519_dalek::StaticSecret {
|
||||
static_private
|
||||
}
|
||||
|
||||
pub fn peer_static_public_key() -> x25519_dalek::PublicKey {
|
||||
// A single static public key is used during development
|
||||
pub fn peer_static_pairs(raw_pairs: Vec<PeerPair>) -> Vec<Peer> {
|
||||
raw_pairs
|
||||
.into_iter()
|
||||
.filter_map(|pair| {
|
||||
if let Ok(peer_static_public_bytes) = decode_base64_key(&pair.public_key) {
|
||||
let peer_static_public = x25519_dalek::PublicKey::from(peer_static_public_bytes);
|
||||
let mut peer = Peer::new(Key::new(peer_static_public.to_bytes()));
|
||||
|
||||
// Read from NYM_PEER_PUBLIC_KEY env variable
|
||||
let peer = std::env::var("NYM_PEER_PUBLIC_KEY").expect("NYM_PEER_PUBLIC_KEY must be set");
|
||||
|
||||
let peer_static_public_bytes: [u8; 32] = decode_base64_key(&peer);
|
||||
let peer_static_public = x25519_dalek::PublicKey::from(peer_static_public_bytes);
|
||||
info!(
|
||||
"Adding wg peer public key: {}",
|
||||
general_purpose::STANDARD.encode(peer_static_public)
|
||||
);
|
||||
peer_static_public
|
||||
}
|
||||
|
||||
pub fn peer_allowed_ips() -> ip_network::IpNetwork {
|
||||
let key: IpAddr = ALLOWED_IPS.parse().unwrap();
|
||||
let cidr = 32u8;
|
||||
ip_network::IpNetwork::new_truncate(key, cidr).unwrap()
|
||||
if let Ok(key) = pair.addr.parse::<IpAddr>() {
|
||||
let peer_ip = ip_network::IpNetwork::new_truncate(key, 32u8)
|
||||
.expect("Netmask should be correct");
|
||||
let peer_ip_mask =
|
||||
IpAddrMask::new(peer_ip.network_address(), peer_ip.netmask());
|
||||
peer.set_allowed_ips(vec![peer_ip_mask]);
|
||||
Some(peer)
|
||||
} else {
|
||||
warn!("Not adding {:?} as IP doesn't parse", pair);
|
||||
None
|
||||
}
|
||||
} else {
|
||||
warn!("Not adding {:?} as public key doesn't decode", pair);
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
@@ -104,8 +104,16 @@ unlicensed = "deny"
|
||||
# See https://spdx.org/licenses/ for list of possible licenses
|
||||
# [possible values: any SPDX 3.11 short identifier (+ optional exception)].
|
||||
allow = [
|
||||
#"MIT",
|
||||
#"Apache-2.0",
|
||||
"MIT",
|
||||
"Apache-2.0",
|
||||
"BSD-2-Clause",
|
||||
"BSD-3-Clause",
|
||||
"ISC",
|
||||
"0BSD",
|
||||
"MPL-2.0",
|
||||
"CC0-1.0",
|
||||
"Unicode-DFS-2016",
|
||||
"OpenSSL",
|
||||
]
|
||||
# List of explicitly disallowed licenses
|
||||
# See https://spdx.org/licenses/ for list of possible licenses
|
||||
@@ -143,22 +151,22 @@ exceptions = [
|
||||
# Some crates don't have (easily) machine readable licensing information,
|
||||
# adding a clarification entry for it allows you to manually specify the
|
||||
# licensing information
|
||||
#[[licenses.clarify]]
|
||||
[[licenses.clarify]]
|
||||
# The name of the crate the clarification applies to
|
||||
#name = "ring"
|
||||
name = "ring"
|
||||
# The optional version constraint for the crate
|
||||
#version = "*"
|
||||
version = "*"
|
||||
# The SPDX expression for the license requirements of the crate
|
||||
#expression = "MIT AND ISC AND OpenSSL"
|
||||
expression = "MIT AND ISC AND OpenSSL"
|
||||
# One or more files in the crate's source used as the "source of truth" for
|
||||
# the license expression. If the contents match, the clarification will be used
|
||||
# when running the license check, otherwise the clarification will be ignored
|
||||
# and the crate will be checked normally, which may produce warnings or errors
|
||||
# depending on the rest of your configuration
|
||||
#license-files = [
|
||||
license-files = [
|
||||
# Each entry is a crate relative path, and the (opaque) hash of its contents
|
||||
#{ path = "LICENSE", hash = 0xbd0eed23 }
|
||||
#]
|
||||
{ path = "LICENSE", hash = 0xbd0eed23 }
|
||||
]
|
||||
|
||||
[licenses.private]
|
||||
# If true, ignores workspace crates that aren't published, or are only
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
- [Querying the Chain](tutorials/cosmos-service/querying.md)
|
||||
|
||||
- [Typescript](tutorials/typescript.md)
|
||||
- [[DEPRECATED] Simple Service Provider](tutorials/simple-service-provider/simple-service-provider.md)
|
||||
- [Simple Service Provider](tutorials/simple-service-provider/simple-service-provider.md)
|
||||
- [Tutorial Overview](tutorials/simple-service-provider/overview.md)
|
||||
- [Preparing Your User Client Environment](tutorials/simple-service-provider/preparating-env.md)
|
||||
- [Building Your User Client](tutorials/simple-service-provider/user-client.md)
|
||||
@@ -59,11 +59,12 @@
|
||||
- [Building Your Service Provider](tutorials/simple-service-provider/service-provider.md)
|
||||
- [Sending a Message Through the Mixnet](tutorials/simple-service-provider/sending-message.md)
|
||||
|
||||
# Shipyard Builders Hackathon 2023
|
||||
- [General Info & Resources](shipyard/general.md)
|
||||
- [Hackathon Challenges](shipyard/challenges-overview.md)
|
||||
- [A Note on Infrastructure](shipyard/infra.md)
|
||||
- [Submission Guidelines](shipyard/guidelines.md)
|
||||
[//]: # (TODO make generic )
|
||||
[//]: # (# Shipyard Builders Hackathon 2023 )
|
||||
[//]: # (- [General Info & Resources](shipyard/general.md))
|
||||
[//]: # (- [Hackathon Challenges](shipyard/challenges-overview.md))
|
||||
[//]: # (- [A Note on Infrastructure](shipyard/infra.md))
|
||||
[//]: # (- [Submission Guidelines](shipyard/guidelines.md))
|
||||
|
||||
# Events
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ Since this is the file where client creation and message parsing are handled, th
|
||||
Below this are the chain-related `const` variables. These have been hardcoded for this demo.
|
||||
|
||||
```rust
|
||||
pub const DEFAULT_VALIDATOR_RPC: &str = "https://sandbox-validator1.nymtech.net";
|
||||
pub const DEFAULT_VALIDATOR_RPC: &str = "https://rpc.sandbox.nymtech.net";
|
||||
pub const DEFAULT_DENOM: &str = "unym";
|
||||
pub const DEFAULT_PREFIX: &str = "n";
|
||||
```
|
||||
|
||||
@@ -28,7 +28,7 @@ COCONUT_DKG_CONTRACT_ADDRESS="nymt1gwk6muhmzeuxje7df7rjvqwl2vex0kj4t2hwuzmyx5k62
|
||||
GROUP_CONTRACT_ADDRESS="nymt14ry36mwauycz08v8ndcujghxz4hmua5epxcn0mamlr3suqe0l2qsqx5ya2"
|
||||
|
||||
STATISTICS_SERVICE_DOMAIN_ADDRESS="http://0.0.0.0"
|
||||
NYXD="https://sandbox-validator1.nymtech.net"
|
||||
NYXD="https://rpc.sandbox.nymtech.net"
|
||||
NYM_API="https://sandbox-validator1-api.nymtech.net/api"
|
||||
```
|
||||
|
||||
@@ -44,7 +44,7 @@ Next, you init the nym-client with the enabled credentials mode set to true:
|
||||
|
||||
Using the new credentials binary, purchase some credentials for the client. The recovery directory is a directory where the credentials will be temporarily stored in case the request fails.
|
||||
|
||||
```./credential --config-env-file <path-to>sandbox.env run --client-home-directory <path-to-the-client-config> --nyxd-url https://sandbox-validator1.nymtech.net --mnemonic "<mnemonic of the account created above>" --amount 50 --recovery-dir <a-path> ```
|
||||
```./credential --config-env-file <path-to>sandbox.env run --client-home-directory <path-to-the-client-config> --nyxd-url https://rpc.sandbox.nymtech.net --mnemonic "<mnemonic of the account created above>" --amount 50 --recovery-dir <a-path> ```
|
||||
|
||||
You can redeem this now by running the nym-client, in enabled credentials mode:
|
||||
|
||||
@@ -62,7 +62,7 @@ Now time to init the socks5 client:
|
||||
|
||||
Purchase credentials for this now too:
|
||||
|
||||
`./credential --config-env-file <path-to>sandbox.env run --client-home-directory <path-to-socks5-config> --nyxd-url https://sandbox-validator1.nymtech.net --mnemonic "<any valid sandbox mnemonic>" --amount 100 --recovery-dir <a-path>`
|
||||
`./credential --config-env-file <path-to>sandbox.env run --client-home-directory <path-to-socks5-config> --nyxd-url https://rpc.sandbox.nymtech.net --mnemonic "<any valid sandbox mnemonic>" --amount 100 --recovery-dir <a-path>`
|
||||
|
||||
Run the socks5 client:
|
||||
|
||||
|
||||
@@ -60,6 +60,9 @@ Quite a bit of stuff gets built. The key working parts are:
|
||||
* [socks5 client](../clients/socks5-client.md): `nym-socks5-client`
|
||||
* [network requester](../nodes/network-requester.md): `nym-network-requester`
|
||||
* [nym-cli tool](../tools/nym-cli.md): `nym-cli`
|
||||
* [nym-api](https://nymtech.net/operators/nodes/nym-api.html): `nym-api`
|
||||
|
||||
[//]: # (* [nymvisor](https://nymtech.net/operators/nodes/nymvisor-upgrade.html): `nymvisor`)
|
||||
|
||||
The repository also contains Typescript applications which aren't built in this process. These can be built by following the instructions on their respective docs pages.
|
||||
* [Nym Wallet](../wallet/desktop-wallet.md)
|
||||
|
||||
@@ -4,9 +4,9 @@ This is Nym's technical documentation, containing information and setup guides a
|
||||
|
||||
If you are new to Nym and want to learn about the Mixnet, explore kickstart options and demos, learn how to integrate with the network, and follow developer tutorials check out the [Developer Portal](https://nymtech.net/developers/) where you can find also our [FAQ section](https://nymtech.net/developers/faq/general-faq.html).
|
||||
|
||||
If you are looking for information and setup guides for the various pieces of Nym Mixnet infrastructure (Mix Nodes, Gateways and Network Requesters) and Nyx blockchain validators see the **new [Operators Guides](https://nymtech.net/operators)** book.
|
||||
If you are looking for information and setup guides for the various pieces of Nym Mixnet infrastructure (Mix Nodes, Gateways and Network Requesters) and Nyx blockchain validators see the [Operators Guides](https://nymtech.net/operators) book.
|
||||
|
||||
If you're specifically looking for TypeScript/JavaScript related information such as SDKs to build your own tools, step-by-step tutorials, live playgrounds and more - make sure to check out the **new [TS SDK Handbook](https://sdk.nymtech.net/)** !
|
||||
If you're specifically looking for TypeScript/JavaScript related information such as SDKs to build your own tools, step-by-step tutorials, live playgrounds and more - check out the [TS SDK Handbook](https://sdk.nymtech.net/).
|
||||
|
||||
## Popular pages
|
||||
**Network Architecture:**
|
||||
|
||||
@@ -17,7 +17,11 @@
|
||||
- [Gateway](nodes/gateway-setup.md)
|
||||
- [Network Requester](nodes/network-requester-setup.md)
|
||||
- [Nyx Validator Setup](nodes/validator-setup.md)
|
||||
- [Nym API Setup](nodes/nym-api.md)
|
||||
- [Maintenance](nodes/maintenance.md)
|
||||
- [Manual Node Upgrade](nodes/manual-upgrade.md)
|
||||
|
||||
[//]: # ( - [Automatic Node Upgrade: Nymvisor Setup and Usage](nodes/nymvisor-upgrade.md))
|
||||
- [Troubleshooting](nodes/troubleshooting.md)
|
||||
|
||||
# FAQ
|
||||
|
||||
@@ -61,7 +61,10 @@ Quite a bit of stuff gets built. The key working parts are:
|
||||
* [webassembly client](https://nymtech.net/docs/clients/webassembly-client.html): `webassembly-client`
|
||||
* [network requester](../nodes/network-requester-setup.md): `nym-network-requester`
|
||||
* [nym-cli tool](https://nymtech.net/docs/tools/nym-cli.html): `nym-cli`
|
||||
* [nym-api](../nodes/nym-api.md): `nym-api`
|
||||
|
||||
[//]: # (* [nymvisor](../nodes/nymvisor-upgrade.md): `nymvisor`)
|
||||
|
||||
The repository also contains Typescript applications which aren't built in this process. These can be built by following the instructions on their respective docs pages.
|
||||
* [Nym Wallet](https://nymtech.net/docs/wallet/desktop-wallet.html)
|
||||
* [Nym Connect](https://nymtech.net/developers/quickstart/nymconnect-gui.html)
|
||||
|
||||
@@ -84,7 +84,7 @@ Additionally
|
||||
|
||||
#### Add Network Requester to an existing Gateway
|
||||
|
||||
If you already [upgraded](./maintenance.md#upgrading-your-node) your Gateway to the [latest version](./gateway-setup.md#current-version) and initialised without a Network Requester, you can easily change its functionality to Exit Gateway with a command `setup-network-requester`.
|
||||
If you already [upgraded](./manual-upgrade.md) your Gateway to the [latest version](./gateway-setup.md#current-version) and initialised without a Network Requester, you can easily change its functionality to Exit Gateway with a command `setup-network-requester`.
|
||||
|
||||
See the options:
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user