Compare commits
2 Commits
ccc
..
hacking-state
| Author | SHA1 | Date | |
|---|---|---|---|
| a0c29f1d17 | |||
| 7abfe27e57 |
@@ -1,21 +0,0 @@
|
||||
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,7 +9,6 @@
|
||||
target
|
||||
.env
|
||||
.env.dev
|
||||
envs/devnet.env
|
||||
/.vscode/settings.json
|
||||
validator/.vscode
|
||||
sample-configs/validator-config.toml
|
||||
|
||||
Generated
+87
-36
@@ -987,13 +987,27 @@ checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae"
|
||||
|
||||
[[package]]
|
||||
name = "bls12_381"
|
||||
version = "0.8.0"
|
||||
source = "git+https://github.com/jstuczyn/bls12_381?branch=feature/gt-serialization-0.8.0#c4543fde7d02efea6ecfcf22e14476ddb516b483"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54757888b09a69be70b5ec303e382a74227392086ba808cb01eeca29233a2397"
|
||||
dependencies = [
|
||||
"digest 0.9.0",
|
||||
"ff 0.13.0",
|
||||
"group 0.13.0",
|
||||
"pairing",
|
||||
"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",
|
||||
"rand_core 0.6.4",
|
||||
"subtle 2.4.1",
|
||||
"zeroize",
|
||||
@@ -3016,6 +3030,26 @@ 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"
|
||||
@@ -3032,7 +3066,6 @@ 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",
|
||||
]
|
||||
@@ -3486,6 +3519,30 @@ 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"
|
||||
@@ -4229,15 +4286,6 @@ 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"
|
||||
@@ -5889,7 +5937,6 @@ dependencies = [
|
||||
"futures-util",
|
||||
"getset",
|
||||
"humantime-serde",
|
||||
"itertools 0.12.0",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"nym-api-requests",
|
||||
@@ -5954,12 +6001,10 @@ dependencies = [
|
||||
"cosmwasm-std",
|
||||
"getset",
|
||||
"nym-coconut-interface",
|
||||
"nym-crypto",
|
||||
"nym-mixnet-contract-common",
|
||||
"nym-node-requests",
|
||||
"schemars",
|
||||
"serde",
|
||||
"tendermint",
|
||||
"ts-rs",
|
||||
]
|
||||
|
||||
@@ -5977,7 +6022,6 @@ dependencies = [
|
||||
"rand 0.7.3",
|
||||
"thiserror",
|
||||
"url",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6213,14 +6257,14 @@ dependencies = [
|
||||
name = "nym-coconut"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"bls12_381",
|
||||
"bls12_381 0.6.0",
|
||||
"bs58 0.4.0",
|
||||
"criterion",
|
||||
"digest 0.9.0",
|
||||
"doc-comment",
|
||||
"ff 0.13.0",
|
||||
"ff 0.11.1",
|
||||
"getrandom 0.2.10",
|
||||
"group 0.13.0",
|
||||
"group 0.11.0",
|
||||
"itertools 0.10.5",
|
||||
"nym-dkg",
|
||||
"nym-pemstore",
|
||||
@@ -6230,7 +6274,6 @@ dependencies = [
|
||||
"serde_derive",
|
||||
"sha2 0.9.9",
|
||||
"thiserror",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6321,7 +6364,7 @@ dependencies = [
|
||||
name = "nym-credentials"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bls12_381",
|
||||
"bls12_381 0.5.0",
|
||||
"cosmrs",
|
||||
"log",
|
||||
"nym-api-requests",
|
||||
@@ -6330,7 +6373,6 @@ dependencies = [
|
||||
"nym-validator-client",
|
||||
"rand 0.7.3",
|
||||
"thiserror",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6364,11 +6406,11 @@ name = "nym-dkg"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitvec",
|
||||
"bls12_381",
|
||||
"bls12_381 0.6.0",
|
||||
"bs58 0.4.0",
|
||||
"criterion",
|
||||
"ff 0.13.0",
|
||||
"group 0.13.0",
|
||||
"ff 0.11.1",
|
||||
"group 0.11.0",
|
||||
"lazy_static",
|
||||
"nym-contracts-common",
|
||||
"nym-pemstore",
|
||||
@@ -7840,11 +7882,20 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pairing"
|
||||
version = "0.23.0"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81fec4625e73cf41ef4bb6846cafa6d44736525f442ba45e407c4a000a13996f"
|
||||
checksum = "7de9d09263c9966e8196fe0380c9dbbc7ea114b5cf371ba29004bc1f9c6db7f3"
|
||||
dependencies = [
|
||||
"group 0.13.0",
|
||||
"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",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -9739,9 +9790,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.108"
|
||||
version = "1.0.107"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
|
||||
checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
@@ -10963,16 +11014,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.10"
|
||||
version = "0.7.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15"
|
||||
checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-util",
|
||||
"hashbrown 0.14.1",
|
||||
"hashbrown 0.12.3",
|
||||
"pin-project-lite 0.2.13",
|
||||
"slab",
|
||||
"tokio",
|
||||
|
||||
+1
-11
@@ -162,8 +162,7 @@ serde_json = "1.0.91"
|
||||
tap = "1.0.1"
|
||||
time = "0.3.30"
|
||||
thiserror = "1.0.48"
|
||||
tokio = "1.33.0"
|
||||
tokio-util = "0.7.10"
|
||||
tokio = "1.24.1"
|
||||
tokio-tungstenite = "0.20.1"
|
||||
tracing = "0.1.37"
|
||||
tungstenite = { version = "0.20.1", default-features = false }
|
||||
@@ -173,14 +172,6 @@ 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"
|
||||
@@ -201,7 +192,6 @@ 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,7 +5,6 @@ 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,7 +3,6 @@ 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,7 +5,6 @@ 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,7 +2,6 @@
|
||||
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,7 +2,6 @@
|
||||
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
|
||||
|
||||
@@ -11,7 +10,6 @@ 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;
|
||||
use nym_coconut_interface::{Base58, Parameters};
|
||||
use nym_credential_storage::storage::Storage;
|
||||
use nym_credentials::coconut::bandwidth::BandwidthVoucher;
|
||||
use nym_credentials::coconut::bandwidth::{BandwidthVoucher, TOTAL_ATTRIBUTES};
|
||||
use nym_credentials::coconut::utils::obtain_aggregate_signature;
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
use nym_network_defaults::VOUCHER_INFO;
|
||||
@@ -12,8 +12,10 @@ 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::State;
|
||||
use state::{KeyPair, State};
|
||||
use std::str::FromStr;
|
||||
|
||||
pub mod state;
|
||||
|
||||
@@ -22,29 +24,30 @@ where
|
||||
C: CoconutBandwidthSigningClient + Sync,
|
||||
{
|
||||
let mut rng = OsRng;
|
||||
let signing_key = identity::PrivateKey::new(&mut rng);
|
||||
let encryption_key = encryption::PrivateKey::new(&mut rng);
|
||||
let params = BandwidthVoucher::default_parameters();
|
||||
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 voucher_value = amount.amount.to_string();
|
||||
|
||||
let tx_hash = client
|
||||
.deposit(
|
||||
amount,
|
||||
String::from(VOUCHER_INFO),
|
||||
signing_key.public_key().to_base58_string(),
|
||||
encryption_key.public_key().to_base58_string(),
|
||||
signing_keypair.public_key.clone(),
|
||||
encryption_keypair.public_key.clone(),
|
||||
None,
|
||||
)
|
||||
.await?
|
||||
.transaction_hash;
|
||||
.transaction_hash
|
||||
.to_string();
|
||||
|
||||
let voucher = BandwidthVoucher::new(
|
||||
¶ms,
|
||||
voucher_value,
|
||||
VOUCHER_INFO.to_string(),
|
||||
tx_hash,
|
||||
signing_key,
|
||||
encryption_key,
|
||||
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)?,
|
||||
);
|
||||
|
||||
let state = State { voucher, params };
|
||||
|
||||
@@ -2,7 +2,32 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use nym_coconut_interface::Parameters;
|
||||
use nym_credentials::coconut::bandwidth::BandwidthVoucher;
|
||||
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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct State {
|
||||
pub voucher: BandwidthVoucher,
|
||||
@@ -13,7 +38,7 @@ impl State {
|
||||
pub fn new(voucher: BandwidthVoucher) -> Self {
|
||||
State {
|
||||
voucher,
|
||||
params: BandwidthVoucher::default_parameters(),
|
||||
params: Parameters::new(TOTAL_ATTRIBUTES).unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ 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::{
|
||||
@@ -47,12 +46,10 @@ 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 = 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 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 signature =
|
||||
nym_coconut_interface::Signature::try_from_bs58(bandwidth_credential.signature)?;
|
||||
let epoch_id = u64::from_str(&bandwidth_credential.epoch_id)
|
||||
@@ -67,8 +64,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,7 +4,6 @@ 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
|
||||
|
||||
|
||||
+1
-3
@@ -127,9 +127,7 @@ impl ActionController {
|
||||
.insert(frag_id, (Arc::new(pending_ack), None))
|
||||
.is_some()
|
||||
{
|
||||
// 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!")
|
||||
panic!("Tried to insert duplicate pending ack")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,7 +259,6 @@ 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::debug!("Setting up gateway");
|
||||
log::trace!("Setting up gateway");
|
||||
match setup {
|
||||
GatewaySetup::MustLoad => use_loaded_gateway_details(key_store, details_store).await,
|
||||
GatewaySetup::New {
|
||||
|
||||
@@ -3,7 +3,6 @@ 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,7 +792,6 @@ 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,15 +3,14 @@ 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 = { workspace = true, features = ["time", "net", "rt"] }
|
||||
tokio-util = { workspace = true, features = ["codec"] }
|
||||
tokio = { version = "1.24.1", features = ["time", "net", "rt"] }
|
||||
tokio-util = { version = "0.7.4", features = ["codec"] }
|
||||
|
||||
# internal
|
||||
nym-sphinx = { path = "../../nymsphinx" }
|
||||
|
||||
@@ -4,7 +4,6 @@ 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,12 +5,8 @@ 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, CredentialsRequestBody, VerifyCredentialBody,
|
||||
VerifyCredentialResponse,
|
||||
BlindSignRequestBody, BlindedSignatureResponse, VerifyCredentialBody, VerifyCredentialResponse,
|
||||
};
|
||||
use nym_api_requests::models::{
|
||||
ComputeRewardEstParam, DescribedGateway, GatewayBondAnnotated, GatewayCoreStatusResponse,
|
||||
@@ -19,7 +15,6 @@ 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;
|
||||
@@ -404,60 +399,6 @@ 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,9 +17,6 @@ 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, verification_key, encryption_key),
|
||||
data: DepositData::new(info.to_string(), verification_key, encryption_key),
|
||||
};
|
||||
self.execute_coconut_bandwidth_contract(
|
||||
fee,
|
||||
|
||||
+2
-22
@@ -6,8 +6,8 @@ use crate::nyxd::error::NyxdError;
|
||||
use crate::nyxd::CosmWasmClient;
|
||||
use async_trait::async_trait;
|
||||
use cw3::{
|
||||
ProposalListResponse, ProposalResponse, VoteListResponse, VoteResponse, VoterDetail,
|
||||
VoterListResponse, VoterResponse,
|
||||
ProposalListResponse, ProposalResponse, VoteListResponse, VoteResponse, VoterListResponse,
|
||||
VoterResponse,
|
||||
};
|
||||
use cw_utils::ThresholdResponse;
|
||||
use nym_multisig_contract_common::msg::QueryMsg as MultisigQueryMsg;
|
||||
@@ -114,26 +114,6 @@ 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]
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
// 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,10 +47,6 @@ 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},
|
||||
@@ -71,7 +67,6 @@ pub mod contract_traits;
|
||||
pub mod cosmwasm_client;
|
||||
pub mod error;
|
||||
pub mod fee;
|
||||
pub mod helpers;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Config {
|
||||
|
||||
@@ -3,7 +3,6 @@ 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,14 +21,10 @@ 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,
|
||||
}
|
||||
@@ -68,12 +64,14 @@ impl Credential {
|
||||
|
||||
pub fn verify(&self, verification_key: &VerificationKey) -> bool {
|
||||
let params = Parameters::new(self.n_params).unwrap();
|
||||
|
||||
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)
|
||||
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)
|
||||
}
|
||||
|
||||
pub fn as_bytes(&self) -> Vec<u8> {
|
||||
@@ -182,8 +180,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,7 +3,6 @@ name = "nym-cli-commands"
|
||||
version = "1.0.0"
|
||||
authors.workspace = true
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
|
||||
@@ -26,10 +26,6 @@ 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,7 +3,6 @@ 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
|
||||
|
||||
@@ -18,4 +17,4 @@ url = { workspace = true }
|
||||
nym-network-defaults = { path = "../network-defaults" }
|
||||
|
||||
[features]
|
||||
default = ["dirs"]
|
||||
default = ["dirs"]
|
||||
@@ -2,7 +2,6 @@
|
||||
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
|
||||
|
||||
@@ -13,4 +12,4 @@ cw2 = { workspace = true, optional = true }
|
||||
nym-multisig-contract-common = { path = "../multisig-contract" }
|
||||
|
||||
[features]
|
||||
schema = ["cw2"]
|
||||
schema = ["cw2"]
|
||||
@@ -4,9 +4,6 @@
|
||||
// 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,7 +2,6 @@
|
||||
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
|
||||
|
||||
@@ -15,4 +14,4 @@ contracts-common = { path = "../contracts-common", package = "nym-contracts-comm
|
||||
nym-multisig-contract-common = { path = "../multisig-contract" }
|
||||
|
||||
[features]
|
||||
schema = []
|
||||
schema = []
|
||||
@@ -174,19 +174,17 @@ impl Display for EpochState {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
EpochState::PublicKeySubmission { resharing } => {
|
||||
write!(f, "PublicKeySubmission (resharing: {resharing})")
|
||||
}
|
||||
EpochState::DealingExchange { resharing } => {
|
||||
write!(f, "DealingExchange (resharing: {resharing})")
|
||||
write!(f, "PublicKeySubmission with resharing {resharing}")
|
||||
}
|
||||
EpochState::DealingExchange { resharing } => write!(f, "DealingExchange {resharing}"),
|
||||
EpochState::VerificationKeySubmission { resharing } => {
|
||||
write!(f, "VerificationKeySubmission (resharing: {resharing})")
|
||||
write!(f, "VerificationKeySubmission with resharing {resharing}")
|
||||
}
|
||||
EpochState::VerificationKeyValidation { resharing } => {
|
||||
write!(f, "VerificationKeyValidation (resharing: {resharing})")
|
||||
write!(f, "VerificationKeyValidation with resharing {resharing}")
|
||||
}
|
||||
EpochState::VerificationKeyFinalization { resharing } => {
|
||||
write!(f, "VerificationKeyFinalization (resharing: {resharing})")
|
||||
write!(f, "VerificationKeyFinalization with resharing {resharing}")
|
||||
}
|
||||
EpochState::InProgress => write!(f, "InProgress"),
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
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
|
||||
|
||||
@@ -14,4 +13,4 @@ cw-utils = { workspace = true }
|
||||
contracts-common = { path = "../contracts-common", package = "nym-contracts-common" }
|
||||
|
||||
[features]
|
||||
schema = []
|
||||
schema = []
|
||||
@@ -2,7 +2,6 @@
|
||||
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,7 +2,6 @@
|
||||
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,7 +2,6 @@
|
||||
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
|
||||
|
||||
@@ -17,4 +16,4 @@ serde = { workspace = true, features = ["derive"] }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
[features]
|
||||
schema = ["cw2"]
|
||||
schema = ["cw2"]
|
||||
@@ -2,7 +2,6 @@
|
||||
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
|
||||
|
||||
@@ -16,4 +15,4 @@ nym-contracts-common = { path = "../contracts-common", version = "0.5.0" }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
[features]
|
||||
schema = ["cw2"]
|
||||
schema = ["cw2"]
|
||||
@@ -2,7 +2,6 @@
|
||||
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,7 +2,6 @@
|
||||
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,20 +2,18 @@
|
||||
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 = { workspace = true, default-features = false, features = ["pairings", "alloc", "experimental"] }
|
||||
bls12_381 = { version = "0.5", 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"] }
|
||||
nym-crypto = { path = "../crypto", features = ["rand", "asymmetric", "symmetric", "hashing"] }
|
||||
nym-api-requests = { path = "../../nym-api/nym-api-requests" }
|
||||
nym-validator-client = { path = "../client-libs/validator-client", default-features = false }
|
||||
|
||||
|
||||
@@ -13,60 +13,38 @@ 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;
|
||||
|
||||
#[derive(Zeroize, ZeroizeOnDrop)]
|
||||
pub const PUBLIC_ATTRIBUTES: u32 = 2;
|
||||
pub const PRIVATE_ATTRIBUTES: u32 = 2;
|
||||
pub const TOTAL_ATTRIBUTES: u32 = PUBLIC_ATTRIBUTES + PRIVATE_ATTRIBUTES;
|
||||
|
||||
pub struct BandwidthVoucher {
|
||||
// private attributes
|
||||
/// a random secret value generated by the client used for double-spending detection
|
||||
// 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,
|
||||
|
||||
// public atttributes:
|
||||
/// the plain text value (e.g., bandwidth) encoded in this voucher
|
||||
// TODO: in another PR change the value from `"1000"` to `"1000unym"`
|
||||
// the value (e.g., bandwidth) encoded in this voucher
|
||||
voucher_value: PublicAttribute,
|
||||
// the plain text value (e.g., bandwidth) encoded in this voucher
|
||||
voucher_value_plain: String,
|
||||
|
||||
/// the plain text information
|
||||
// a field with public information, e.g., type of voucher, interval etc.
|
||||
voucher_info: PublicAttribute,
|
||||
// the plain text information
|
||||
voucher_info_plain: String,
|
||||
|
||||
/// 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)]
|
||||
// the hash of the deposit transaction
|
||||
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
|
||||
unused_ed25519: encryption::PrivateKey,
|
||||
|
||||
// base58 encoded private key ensuring only this client receives the signature share
|
||||
encryption_key: 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,
|
||||
@@ -79,26 +57,24 @@ 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_prehashed = hash_to_scalar(voucher_value);
|
||||
let _voucher_info_prehashed = hash_to_scalar(voucher_info);
|
||||
|
||||
let voucher_value = hash_to_scalar(voucher_value.as_bytes());
|
||||
let voucher_info = hash_to_scalar(voucher_info.as_bytes());
|
||||
let (pedersen_commitments_openings, blind_sign_request) = prepare_blind_sign(
|
||||
params,
|
||||
&[&serial_number, &binding_number],
|
||||
&[&_voucher_value_prehashed, &_voucher_info_prehashed],
|
||||
&[serial_number, binding_number],
|
||||
&[voucher_value, voucher_info],
|
||||
)
|
||||
.unwrap();
|
||||
BandwidthVoucher {
|
||||
serial_number,
|
||||
binding_number,
|
||||
_voucher_value_prehashed,
|
||||
voucher_value,
|
||||
voucher_value_plain,
|
||||
_voucher_info_prehashed,
|
||||
voucher_info,
|
||||
voucher_info_plain,
|
||||
tx_hash,
|
||||
signing_key,
|
||||
unused_ed25519: encryption_key,
|
||||
encryption_key,
|
||||
pedersen_commitments_openings,
|
||||
blind_sign_request,
|
||||
}
|
||||
@@ -111,7 +87,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.unused_ed25519.to_bytes();
|
||||
let encryption_key_b = self.encryption_key.to_bytes();
|
||||
let blind_sign_request_b = self.blind_sign_request.to_bytes();
|
||||
|
||||
let mut ret = Vec::new();
|
||||
@@ -195,13 +171,13 @@ impl BandwidthVoucher {
|
||||
bytes[var_length_pointer..var_length_pointer + voucher_value_plain_no].to_vec(),
|
||||
)
|
||||
.or_else(utf_err)?;
|
||||
let _voucher_value_prehashed = hash_to_scalar(&voucher_value_plain);
|
||||
let voucher_value = 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_prehashed = hash_to_scalar(&voucher_info_plain);
|
||||
let voucher_info = 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],
|
||||
@@ -220,43 +196,36 @@ impl BandwidthVoucher {
|
||||
Ok(Self {
|
||||
serial_number,
|
||||
binding_number,
|
||||
_voucher_value_prehashed,
|
||||
voucher_value,
|
||||
voucher_value_plain,
|
||||
_voucher_info_prehashed,
|
||||
voucher_info,
|
||||
voucher_info_plain,
|
||||
tx_hash,
|
||||
signing_key,
|
||||
unused_ed25519: encryption_key,
|
||||
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_prehashed,
|
||||
&self._voucher_info_prehashed,
|
||||
]
|
||||
}
|
||||
|
||||
pub fn identity_key(&self) -> &identity::PrivateKey {
|
||||
&self.signing_key
|
||||
pub fn get_public_attributes(&self) -> Vec<PublicAttribute> {
|
||||
vec![self.voucher_value, self.voucher_info]
|
||||
}
|
||||
|
||||
pub fn encryption_key(&self) -> &encryption::PrivateKey {
|
||||
&self.unused_ed25519
|
||||
&self.encryption_key
|
||||
}
|
||||
|
||||
pub fn pedersen_commitments_openings(&self) -> &Vec<Attribute> {
|
||||
@@ -278,32 +247,27 @@ 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 signable_plaintext(request: &BlindSignRequest, tx_hash: Hash) -> Vec<u8> {
|
||||
pub fn sign(&self, request: &BlindSignRequest) -> identity::Signature {
|
||||
let mut message = request.to_bytes();
|
||||
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)
|
||||
message.extend_from_slice(self.tx_hash.to_string().as_bytes());
|
||||
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(BandwidthVoucher::ENCODED_ATTRIBUTES)?;
|
||||
let params = Parameters::new(TOTAL_ATTRIBUTES)?;
|
||||
|
||||
prepare_credential_for_spending(
|
||||
¶ms,
|
||||
@@ -352,30 +316,24 @@ 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.unused_ed25519.to_string(),
|
||||
deserialized_voucher.unused_ed25519.to_string()
|
||||
voucher.encryption_key.to_string(),
|
||||
deserialized_voucher.encryption_key.to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
voucher.pedersen_commitments_openings,
|
||||
@@ -413,11 +371,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,4 +2,5 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub mod bandwidth;
|
||||
pub mod params;
|
||||
pub mod utils;
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
// 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,14 +1,18 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::coconut::bandwidth::BandwidthVoucher;
|
||||
use crate::coconut::bandwidth::{BandwidthVoucher, PRIVATE_ATTRIBUTES, PUBLIC_ATTRIBUTES};
|
||||
use crate::coconut::params::{NymApiCredentialEncryptionAlgorithm, NymApiCredentialHkdfAlgorithm};
|
||||
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,
|
||||
Credential, Parameters, Signature, SignatureShare, VerificationKey,
|
||||
BlindedSignature, 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(
|
||||
@@ -32,34 +36,47 @@ pub async fn obtain_aggregate_verification_key(
|
||||
|
||||
async fn obtain_partial_credential(
|
||||
params: &Parameters,
|
||||
voucher: &BandwidthVoucher,
|
||||
attributes: &BandwidthVoucher,
|
||||
client: &nym_validator_client::client::NymApiClient,
|
||||
validator_vk: &VerificationKey,
|
||||
) -> Result<Signature, Error> {
|
||||
let public_attributes_plain = voucher.get_public_attributes_plain();
|
||||
let blind_sign_request = voucher.blind_sign_request();
|
||||
let request_signature = voucher.sign();
|
||||
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 blind_sign_request_body = BlindSignRequestBody::new(
|
||||
blind_sign_request.clone(),
|
||||
voucher.tx_hash(),
|
||||
request_signature,
|
||||
blind_sign_request,
|
||||
attributes.tx_hash().to_string(),
|
||||
attributes.sign(blind_sign_request).to_base58_string(),
|
||||
&public_attributes,
|
||||
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 blinded_signature = response.blinded_signature;
|
||||
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 public_attributes = voucher.get_public_attributes();
|
||||
let private_attributes = voucher.get_private_attributes();
|
||||
let blinded_signature = BlindedSignature::from_bytes(&blinded_signature_bytes)?;
|
||||
|
||||
let unblinded_signature = blinded_signature.unblind_and_verify(
|
||||
let unblinded_signature = blinded_signature.unblind(
|
||||
params,
|
||||
validator_vk,
|
||||
&private_attributes,
|
||||
&public_attributes,
|
||||
&blind_sign_request.get_commitment_hash(),
|
||||
voucher.pedersen_commitments_openings(),
|
||||
attributes.pedersen_commitments_openings(),
|
||||
)?;
|
||||
|
||||
Ok(unblinded_signature)
|
||||
@@ -67,13 +84,16 @@ async fn obtain_partial_credential(
|
||||
|
||||
pub async fn obtain_aggregate_signature(
|
||||
params: &Parameters,
|
||||
voucher: &BandwidthVoucher,
|
||||
attributes: &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()
|
||||
@@ -94,7 +114,7 @@ pub async fn obtain_aggregate_signature(
|
||||
|
||||
match obtain_partial_credential(
|
||||
params,
|
||||
voucher,
|
||||
attributes,
|
||||
&coconut_api_client.api_client,
|
||||
&coconut_api_client.verification_key,
|
||||
)
|
||||
@@ -116,9 +136,6 @@ 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);
|
||||
@@ -133,8 +150,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,
|
||||
@@ -148,7 +165,7 @@ pub fn prepare_credential_for_spending(
|
||||
)?;
|
||||
|
||||
Ok(Credential::new(
|
||||
BandwidthVoucher::ENCODED_ATTRIBUTES,
|
||||
PUBLIC_ATTRIBUTES + PRIVATE_ATTRIBUTES,
|
||||
theta,
|
||||
voucher_value,
|
||||
voucher_info,
|
||||
|
||||
@@ -201,17 +201,6 @@ 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,14 +5,13 @@ 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")]
|
||||
@@ -225,17 +224,6 @@ 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()
|
||||
}
|
||||
@@ -307,7 +295,7 @@ impl PemStorableKey for PrivateKey {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Signature(ed25519_dalek::Signature);
|
||||
|
||||
impl Signature {
|
||||
@@ -331,14 +319,6 @@ 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,7 +3,6 @@ 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
|
||||
|
||||
@@ -12,7 +11,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 = { workspace = true, default-features = false, features = ["alloc", "pairings", "experimental", "zeroize"] }
|
||||
bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", branch ="gt-serialisation", default-features = false, features = ["alloc", "pairings", "experimental", "zeroize"] }
|
||||
nym-contracts-common = { path = "../cosmwasm-smart-contracts/contracts-common", optional = true }
|
||||
bs58 = "0.4"
|
||||
|
||||
@@ -30,11 +29,11 @@ zeroize = { workspace = true, features = ["zeroize_derive"] }
|
||||
nym-pemstore = { path = "../pemstore" }
|
||||
|
||||
[dependencies.group]
|
||||
workspace = true
|
||||
version = "0.11"
|
||||
default-features = false
|
||||
|
||||
[dependencies.ff]
|
||||
workspace = true
|
||||
version = "0.11"
|
||||
default-features = false
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
name = "nym-execute"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
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
|
||||
|
||||
@@ -11,4 +10,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,7 +3,6 @@ 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
|
||||
|
||||
@@ -21,7 +20,7 @@ tokio = { version = "1.24.1", features = [
|
||||
"net",
|
||||
"io-util",
|
||||
] }
|
||||
tokio-util = { workspace = true, features = ["codec"] }
|
||||
tokio-util = { version = "0.7.4", 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)) => {
|
||||
debug!(
|
||||
error!(
|
||||
"The socket connection got corrupted with error: {err}. Closing the socket",
|
||||
);
|
||||
return;
|
||||
}
|
||||
None => {
|
||||
debug!("The socket connection got terminated by the remote!");
|
||||
error!("The socket connection got terminated by the remote!");
|
||||
return;
|
||||
}
|
||||
};
|
||||
@@ -125,7 +125,7 @@ impl ConnectionHandler {
|
||||
.write_all(reply_packet.to_bytes().as_ref())
|
||||
.await
|
||||
{
|
||||
debug!(
|
||||
error!(
|
||||
"Failed to write reply packet back to the sender - {}. Closing the socket on our end",
|
||||
err
|
||||
);
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
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,7 +3,6 @@ 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,12 +3,11 @@ 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 = { workspace = true, default-features = false, features = ["pairings", "alloc", "experimental"] }
|
||||
bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", branch ="gt-serialisation", default-features = false, features = ["pairings", "alloc", "experimental"] }
|
||||
itertools = "0.10"
|
||||
digest = "0.9"
|
||||
rand = "0.8"
|
||||
@@ -17,17 +16,16 @@ 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]
|
||||
workspace = true
|
||||
version = "0.11"
|
||||
default-features = false
|
||||
|
||||
[dependencies.group]
|
||||
workspace = true
|
||||
version = "0.11"
|
||||
default-features = false
|
||||
|
||||
[dev-dependencies]
|
||||
@@ -40,9 +38,7 @@ 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, random_scalars_refs, setup, ttp_keygen, verify_credential,
|
||||
prove_bandwidth_credential, 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_and_verify(
|
||||
.unblind(
|
||||
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();
|
||||
|
||||
random_scalars_refs!(public_attributes, params, case.num_public_attrs as usize);
|
||||
let public_attributes = params.n_random_scalars(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().clone())
|
||||
.map(|keypair| keypair.verification_key())
|
||||
.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,10 +34,7 @@ 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(
|
||||
@@ -115,16 +112,7 @@ impl Bytable for PrivateKey {
|
||||
}
|
||||
|
||||
fn try_from_byte_slice(slice: &[u8]) -> Result<Self> {
|
||||
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)
|
||||
PrivateKey::from_bytes(slice.try_into().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,36 +145,21 @@ impl PublicKey {
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> [u8; 48] {
|
||||
self.0.to_affine().to_compressed()
|
||||
self.to_byte_vec().try_into().unwrap()
|
||||
}
|
||||
|
||||
pub fn from_bytes(bytes: &[u8; 48]) -> Result<PublicKey> {
|
||||
try_deserialize_g1_projective(
|
||||
bytes,
|
||||
CoconutError::Deserialization(
|
||||
"Failed to deserialize compressed ElGamal public key".to_string(),
|
||||
),
|
||||
)
|
||||
.map(PublicKey)
|
||||
Ok(PublicKey::try_from(bytes.to_vec().as_slice()).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl Bytable for PublicKey {
|
||||
fn to_byte_vec(&self) -> Vec<u8> {
|
||||
self.to_bytes().into()
|
||||
self.0.to_affine().to_compressed().into()
|
||||
}
|
||||
|
||||
fn try_from_byte_slice(slice: &[u8]) -> Result<Self> {
|
||||
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)
|
||||
Ok(PublicKey::from_bytes(slice.try_into().unwrap()).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,7 +167,13 @@ impl TryFrom<&[u8]> for PublicKey {
|
||||
type Error = CoconutError;
|
||||
|
||||
fn try_from(slice: &[u8]) -> Result<PublicKey> {
|
||||
PublicKey::try_from_byte_slice(slice)
|
||||
try_deserialize_g1_projective(
|
||||
slice.try_into().unwrap(),
|
||||
CoconutError::Deserialization(
|
||||
"Failed to deserialize compressed ElGamal public key".to_string(),
|
||||
),
|
||||
)
|
||||
.map(PublicKey)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,7 +225,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,20 +50,4 @@ 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,9 +1,11 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#![warn(clippy::expect_used)]
|
||||
#![warn(clippy::unwrap_used)]
|
||||
use std::convert::TryInto;
|
||||
|
||||
use bls12_381::Scalar;
|
||||
|
||||
pub use crate::traits::Bytable;
|
||||
pub use elgamal::elgamal_keygen;
|
||||
pub use elgamal::ElGamalKeyPair;
|
||||
pub use elgamal::PublicKey;
|
||||
@@ -28,7 +30,6 @@ 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;
|
||||
@@ -40,6 +41,18 @@ pub mod tests;
|
||||
mod traits;
|
||||
mod utils;
|
||||
|
||||
pub type Attribute = bls12_381::Scalar;
|
||||
pub type Attribute = 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,8 +162,11 @@ impl ProofCmCs {
|
||||
&challenge,
|
||||
&pedersen_commitments_openings.iter().collect::<Vec<_>>(),
|
||||
);
|
||||
let response_attributes =
|
||||
produce_responses(&witness_attributes, &challenge, private_attributes);
|
||||
let response_attributes = produce_responses(
|
||||
&witness_attributes,
|
||||
&challenge,
|
||||
&private_attributes.iter().collect::<Vec<_>>(),
|
||||
);
|
||||
|
||||
ProofCmCs {
|
||||
challenge,
|
||||
@@ -178,7 +181,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;
|
||||
@@ -200,7 +203,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
|
||||
@@ -277,12 +280,8 @@ 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;
|
||||
|
||||
@@ -298,8 +297,6 @@ 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 {
|
||||
@@ -316,8 +313,6 @@ 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,
|
||||
@@ -467,7 +462,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() != 128 {
|
||||
if bytes.len() < 32 * 4 || (bytes.len()) % 32 != 0 {
|
||||
return Err(CoconutError::DeserializationInvalidLength {
|
||||
actual: bytes.len(),
|
||||
modulus_target: bytes.len(),
|
||||
@@ -477,32 +472,24 @@ 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,
|
||||
@@ -525,13 +512,14 @@ impl ProofKappaZeta {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use group::Group;
|
||||
use rand::thread_rng;
|
||||
|
||||
use crate::scheme::keygen::keygen;
|
||||
use crate::scheme::setup::setup;
|
||||
use crate::scheme::verification::{compute_kappa, compute_zeta};
|
||||
use crate::tests::helpers::random_scalars_refs;
|
||||
use group::Group;
|
||||
use rand::thread_rng;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn proof_cm_cs_bytes_roundtrip() {
|
||||
@@ -542,7 +530,7 @@ mod tests {
|
||||
let r = params.random_scalar();
|
||||
let cms: [G1Projective; 1] = [G1Projective::random(&mut rng)];
|
||||
let rs = params.n_random_scalars(1);
|
||||
random_scalars_refs!(private_attributes, params, 1);
|
||||
let private_attributes = params.n_random_scalars(1);
|
||||
|
||||
// 0 public 1 private
|
||||
let pi_s = ProofCmCs::construct(¶ms, &cm, &r, &cms, &rs, &private_attributes, &[]);
|
||||
@@ -558,7 +546,7 @@ mod tests {
|
||||
G1Projective::random(&mut rng),
|
||||
];
|
||||
let rs = params.n_random_scalars(2);
|
||||
random_scalars_refs!(private_attributes, params, 2);
|
||||
let private_attributes = params.n_random_scalars(2);
|
||||
|
||||
// 0 public 2 privates
|
||||
let pi_s = ProofCmCs::construct(¶ms, &cm, &r, &cms, &rs, &private_attributes, &[]);
|
||||
@@ -574,20 +562,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 = ¶ms.random_scalar();
|
||||
let binding_number = ¶ms.random_scalar();
|
||||
let serial_number = params.random_scalar();
|
||||
let binding_number = params.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,
|
||||
@@ -604,9 +592,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().clone())
|
||||
.map(|keypair| keypair.verification_key())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let aggr_vk1 = aggregate_verification_keys(&vks[..3], Some(&[1, 2, 3])).unwrap();
|
||||
@@ -212,18 +212,13 @@ mod tests {
|
||||
#[test]
|
||||
fn signature_aggregation_works_for_any_subset_of_signatures() {
|
||||
let mut params = Parameters::new(2).unwrap();
|
||||
random_scalars_refs!(attributes, params, 2);
|
||||
let attributes = params.n_random_scalars(2);
|
||||
|
||||
let keypairs = ttp_keygen(¶ms, 3, 5).unwrap();
|
||||
|
||||
let (sks, vks): (Vec<_>, Vec<_>) = keypairs
|
||||
.into_iter()
|
||||
.map(|keypair| {
|
||||
(
|
||||
keypair.secret_key().clone(),
|
||||
keypair.verification_key().clone(),
|
||||
)
|
||||
})
|
||||
.map(|keypair| (keypair.secret_key(), keypair.verification_key()))
|
||||
.unzip();
|
||||
|
||||
let sigs = sks
|
||||
@@ -317,17 +312,12 @@ mod tests {
|
||||
fn signature_aggregation_doesnt_work_for_empty_set_of_signatures() {
|
||||
let signatures: Vec<Signature> = vec![];
|
||||
let params = Parameters::new(2).unwrap();
|
||||
random_scalars_refs!(attributes, params, 2);
|
||||
let attributes = params.n_random_scalars(2);
|
||||
let keypairs = ttp_keygen(¶ms, 3, 5).unwrap();
|
||||
|
||||
let (_, vks): (Vec<_>, Vec<_>) = keypairs
|
||||
.into_iter()
|
||||
.map(|keypair| {
|
||||
(
|
||||
keypair.secret_key().clone(),
|
||||
keypair.verification_key().clone(),
|
||||
)
|
||||
})
|
||||
.map(|keypair| (keypair.secret_key(), keypair.verification_key()))
|
||||
.unzip();
|
||||
|
||||
let aggr_vk_all = aggregate_verification_keys(&vks, None).unwrap();
|
||||
@@ -340,16 +330,11 @@ mod tests {
|
||||
fn signature_aggregation_doesnt_work_if_indices_have_invalid_length() {
|
||||
let signatures = vec![random_signature()];
|
||||
let params = Parameters::new(2).unwrap();
|
||||
random_scalars_refs!(attributes, params, 2);
|
||||
let attributes = params.n_random_scalars(2);
|
||||
let keypairs = ttp_keygen(¶ms, 3, 5).unwrap();
|
||||
let (_, vks): (Vec<_>, Vec<_>) = keypairs
|
||||
.into_iter()
|
||||
.map(|keypair| {
|
||||
(
|
||||
keypair.secret_key().clone(),
|
||||
keypair.verification_key().clone(),
|
||||
)
|
||||
})
|
||||
.map(|keypair| (keypair.secret_key(), keypair.verification_key()))
|
||||
.unzip();
|
||||
let aggr_vk_all = aggregate_verification_keys(&vks, None).unwrap();
|
||||
|
||||
@@ -371,16 +356,11 @@ mod tests {
|
||||
fn signature_aggregation_doesnt_work_for_non_unique_indices() {
|
||||
let signatures = vec![random_signature(), random_signature()];
|
||||
let params = Parameters::new(2).unwrap();
|
||||
random_scalars_refs!(attributes, params, 2);
|
||||
let attributes = params.n_random_scalars(2);
|
||||
let keypairs = ttp_keygen(¶ms, 3, 5).unwrap();
|
||||
let (_, vks): (Vec<_>, Vec<_>) = keypairs
|
||||
.into_iter()
|
||||
.map(|keypair| {
|
||||
(
|
||||
keypair.secret_key().clone(),
|
||||
keypair.verification_key().clone(),
|
||||
)
|
||||
})
|
||||
.map(|keypair| (keypair.secret_key(), keypair.verification_key()))
|
||||
.unzip();
|
||||
let aggr_vk_all = aggregate_verification_keys(&vks, None).unwrap();
|
||||
|
||||
|
||||
@@ -25,8 +25,6 @@ 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,8 +54,6 @@ 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,
|
||||
@@ -65,8 +63,6 @@ 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,
|
||||
@@ -76,8 +72,6 @@ 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 {
|
||||
@@ -92,14 +86,6 @@ 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,
|
||||
@@ -151,7 +137,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,
|
||||
@@ -164,8 +150,8 @@ impl BlindSignRequest {
|
||||
self.commitment_hash
|
||||
}
|
||||
|
||||
pub fn get_private_attributes_pedersen_commitments(&self) -> &[G1Projective] {
|
||||
&self.private_attributes_commitments
|
||||
pub fn get_private_attributes_pedersen_commitments(&self) -> Vec<G1Projective> {
|
||||
self.private_attributes_commitments.clone()
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
@@ -175,16 +161,12 @@ 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();
|
||||
@@ -205,7 +187,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
|
||||
@@ -215,13 +197,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 {
|
||||
@@ -233,8 +215,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(
|
||||
@@ -289,7 +271,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();
|
||||
@@ -322,7 +304,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])
|
||||
@@ -363,7 +345,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 {
|
||||
@@ -401,7 +383,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()
|
||||
@@ -433,7 +415,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 {
|
||||
@@ -447,7 +429,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().copied().sum::<Scalar>();
|
||||
let attributes_sum = public_attributes.iter().sum::<Scalar>();
|
||||
let h = hash_g1((params.gen1() * attributes_sum).to_bytes());
|
||||
|
||||
// x + m0 * y0 + m1 * y1 + ... mn * yn
|
||||
@@ -455,7 +437,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;
|
||||
@@ -466,14 +448,13 @@ 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();
|
||||
random_scalars_refs!(private_attributes, params, 1);
|
||||
random_scalars_refs!(public_attributes, params, 0);
|
||||
let private_attributes = params.n_random_scalars(1);
|
||||
let public_attributes = params.n_random_scalars(0);
|
||||
|
||||
let (_commitments_openings, lambda) =
|
||||
prepare_blind_sign(¶ms, &private_attributes, &public_attributes).unwrap();
|
||||
@@ -486,8 +467,8 @@ mod tests {
|
||||
|
||||
// 2 public and 2 private attributes
|
||||
let params = Parameters::new(4).unwrap();
|
||||
random_scalars_refs!(private_attributes, params, 2);
|
||||
random_scalars_refs!(public_attributes, params, 2);
|
||||
let private_attributes = params.n_random_scalars(2);
|
||||
let public_attributes = params.n_random_scalars(2);
|
||||
|
||||
let (_commitments_openings, lambda) =
|
||||
prepare_blind_sign(¶ms, &private_attributes, &public_attributes).unwrap();
|
||||
@@ -502,8 +483,8 @@ mod tests {
|
||||
#[test]
|
||||
fn successful_verify_partial_blind_signature() {
|
||||
let params = Parameters::new(4).unwrap();
|
||||
random_scalars_refs!(private_attributes, params, 2);
|
||||
random_scalars_refs!(public_attributes, params, 2);
|
||||
let private_attributes = params.n_random_scalars(2);
|
||||
let public_attributes = params.n_random_scalars(2);
|
||||
|
||||
let (_commitments_openings, request) =
|
||||
prepare_blind_sign(¶ms, &private_attributes, &public_attributes).unwrap();
|
||||
@@ -511,7 +492,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,
|
||||
)
|
||||
@@ -522,35 +503,36 @@ 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();
|
||||
random_scalars_refs!(private_attributes, params, 2);
|
||||
let private_attributes = params.n_random_scalars(2);
|
||||
|
||||
let (_commitments_openings, request) =
|
||||
prepare_blind_sign(¶ms, &private_attributes, &[]).unwrap();
|
||||
|
||||
let validator_keypair = keygen(¶ms);
|
||||
let blind_sig = blind_sign(¶ms, validator_keypair.secret_key(), &request, &[]).unwrap();
|
||||
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();
|
||||
random_scalars_refs!(private_attributes, params, 2);
|
||||
random_scalars_refs!(public_attributes, params, 2);
|
||||
let private_attributes = params.n_random_scalars(2);
|
||||
let public_attributes = params.n_random_scalars(2);
|
||||
|
||||
let (_commitments_openings, request) =
|
||||
prepare_blind_sign(¶ms, &private_attributes, &public_attributes).unwrap();
|
||||
@@ -559,7 +541,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,
|
||||
)
|
||||
@@ -571,7 +553,7 @@ mod tests {
|
||||
&request,
|
||||
&public_attributes,
|
||||
&blind_sig,
|
||||
validator2_keypair.verification_key()
|
||||
&validator2_keypair.verification_key()
|
||||
),);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,12 +23,8 @@ use crate::utils::{
|
||||
};
|
||||
use crate::Base58;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(test, derive(PartialEq, Eq, Clone))]
|
||||
#[cfg_attr(
|
||||
feature = "key-zeroize",
|
||||
derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop)
|
||||
)]
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(test, derive(PartialEq, Eq))]
|
||||
pub struct SecretKey {
|
||||
pub(crate) x: Scalar,
|
||||
pub(crate) ys: Vec<Scalar>,
|
||||
@@ -66,9 +62,7 @@ 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;
|
||||
|
||||
@@ -103,10 +97,6 @@ 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();
|
||||
@@ -151,10 +141,6 @@ 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,
|
||||
@@ -194,9 +180,7 @@ 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);
|
||||
@@ -220,8 +204,6 @@ 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,
|
||||
@@ -238,8 +220,6 @@ 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,
|
||||
@@ -412,11 +392,7 @@ impl Bytable for VerificationKey {
|
||||
impl Base58 for VerificationKey {}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[cfg_attr(test, derive(PartialEq, Eq, Clone))]
|
||||
#[cfg_attr(
|
||||
feature = "key-zeroize",
|
||||
derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop)
|
||||
)]
|
||||
#[cfg_attr(test, derive(PartialEq, Eq))]
|
||||
pub struct KeyPair {
|
||||
secret_key: SecretKey,
|
||||
verification_key: VerificationKey,
|
||||
@@ -453,12 +429,12 @@ impl KeyPair {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn secret_key(&self) -> &SecretKey {
|
||||
&self.secret_key
|
||||
pub fn secret_key(&self) -> SecretKey {
|
||||
self.secret_key.clone()
|
||||
}
|
||||
|
||||
pub fn verification_key(&self) -> &VerificationKey {
|
||||
&self.verification_key
|
||||
pub fn verification_key(&self) -> VerificationKey {
|
||||
self.verification_key.clone()
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
@@ -512,8 +488,6 @@ 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;
|
||||
@@ -529,8 +503,6 @@ 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()
|
||||
@@ -543,7 +515,6 @@ 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,10 +44,7 @@ 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(
|
||||
@@ -91,45 +88,6 @@ 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 {
|
||||
@@ -144,7 +102,8 @@ impl Bytable for Signature {
|
||||
|
||||
impl Base58 for Signature {}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(test, derive(PartialEq, Eq))]
|
||||
pub struct BlindedSignature(G1Projective, G1Projective);
|
||||
|
||||
impl Bytable for BlindedSignature {
|
||||
@@ -170,10 +129,7 @@ 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(
|
||||
@@ -192,12 +148,24 @@ 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()
|
||||
@@ -207,27 +175,28 @@ impl BlindedSignature {
|
||||
|
||||
let unblinded_c = c - blinding_removers;
|
||||
|
||||
Ok(Signature(*h, unblinded_c))
|
||||
}
|
||||
let alpha = partial_verification_key.alpha;
|
||||
|
||||
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)
|
||||
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 to_bytes(&self) -> [u8; 96] {
|
||||
@@ -268,25 +237,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 crate::tests::helpers::random_scalars_refs;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn unblind_returns_error_if_integrity_check_on_commitment_hash_fails() {
|
||||
let params = Parameters::new(2).unwrap();
|
||||
random_scalars_refs!(private_attributes, params, 2);
|
||||
let private_attributes = params.n_random_scalars(2_usize);
|
||||
|
||||
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;
|
||||
@@ -294,9 +263,9 @@ mod tests {
|
||||
let wrong_commitments_openings = params.n_random_scalars(private_attributes.len());
|
||||
|
||||
assert!(sig1
|
||||
.unblind_and_verify(
|
||||
.unblind(
|
||||
¶ms,
|
||||
keypair1.verification_key(),
|
||||
&keypair1.verification_key(),
|
||||
&private_attributes,
|
||||
&[],
|
||||
&fake_commitment_hash,
|
||||
@@ -308,23 +277,20 @@ mod tests {
|
||||
#[test]
|
||||
fn unblind_returns_error_if_signature_verification_fails() {
|
||||
let params = Parameters::new(2).unwrap();
|
||||
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 private_attributes = vec![hash_to_scalar("Attribute1"), hash_to_scalar("Attribute2")];
|
||||
let private_attributes2 = vec![hash_to_scalar("Attribute3"), hash_to_scalar("Attribute4")];
|
||||
|
||||
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_and_verify(
|
||||
.unblind(
|
||||
¶ms,
|
||||
keypair1.verification_key(),
|
||||
&keypair1.verification_key(),
|
||||
&private_attributes2,
|
||||
&[],
|
||||
&lambda.get_commitment_hash(),
|
||||
@@ -338,7 +304,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);
|
||||
@@ -346,11 +312,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_and_verify(
|
||||
.unblind(
|
||||
¶ms,
|
||||
keypair1.verification_key(),
|
||||
&keypair1.verification_key(),
|
||||
&private_attributes,
|
||||
&[],
|
||||
&lambda.get_commitment_hash(),
|
||||
@@ -358,11 +324,11 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let sig2 = blind_sign(¶ms, keypair2.secret_key(), &lambda, &[])
|
||||
let sig2 = blind_sign(¶ms, &keypair2.secret_key(), &lambda, &[])
|
||||
.unwrap()
|
||||
.unblind_and_verify(
|
||||
.unblind(
|
||||
¶ms,
|
||||
keypair2.verification_key(),
|
||||
&keypair2.verification_key(),
|
||||
&private_attributes,
|
||||
&[],
|
||||
&lambda.get_commitment_hash(),
|
||||
@@ -372,39 +338,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,
|
||||
&[],
|
||||
));
|
||||
@@ -413,30 +379,30 @@ mod tests {
|
||||
#[test]
|
||||
fn verification_on_two_public_attributes() {
|
||||
let mut params = Parameters::new(2).unwrap();
|
||||
random_scalars_refs!(attributes, params, 2);
|
||||
let attributes = params.n_random_scalars(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,
|
||||
));
|
||||
@@ -445,11 +411,10 @@ mod tests {
|
||||
#[test]
|
||||
fn verification_on_two_public_and_two_private_attributes() {
|
||||
let params = Parameters::new(4).unwrap();
|
||||
random_scalars_refs!(public_attributes, params, 2);
|
||||
|
||||
let public_attributes = params.n_random_scalars(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);
|
||||
@@ -457,11 +422,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_and_verify(
|
||||
.unblind(
|
||||
¶ms,
|
||||
keypair1.verification_key(),
|
||||
&keypair1.verification_key(),
|
||||
&private_attributes,
|
||||
&public_attributes,
|
||||
&lambda.get_commitment_hash(),
|
||||
@@ -469,11 +434,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_and_verify(
|
||||
.unblind(
|
||||
¶ms,
|
||||
keypair2.verification_key(),
|
||||
&keypair2.verification_key(),
|
||||
&private_attributes,
|
||||
&public_attributes,
|
||||
&lambda.get_commitment_hash(),
|
||||
@@ -483,39 +448,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,
|
||||
));
|
||||
@@ -524,11 +489,10 @@ mod tests {
|
||||
#[test]
|
||||
fn verification_on_two_public_and_two_private_attributes_from_two_signers() {
|
||||
let params = Parameters::new(4).unwrap();
|
||||
random_scalars_refs!(public_attributes, params, 2);
|
||||
|
||||
let public_attributes = params.n_random_scalars(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();
|
||||
|
||||
@@ -538,11 +502,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_and_verify(
|
||||
.unblind(
|
||||
¶ms,
|
||||
keypair.verification_key(),
|
||||
&keypair.verification_key(),
|
||||
&private_attributes,
|
||||
&public_attributes,
|
||||
&lambda.get_commitment_hash(),
|
||||
@@ -554,7 +518,7 @@ mod tests {
|
||||
|
||||
let vks = keypairs
|
||||
.into_iter()
|
||||
.map(|keypair| keypair.verification_key().clone())
|
||||
.map(|keypair| keypair.verification_key())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut attributes = Vec::with_capacity(private_attributes.len() + public_attributes.len());
|
||||
@@ -566,14 +530,9 @@ 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,
|
||||
@@ -588,14 +547,9 @@ 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,8 +43,6 @@ 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,
|
||||
@@ -53,8 +51,6 @@ 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,
|
||||
@@ -134,7 +130,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
|
||||
@@ -142,11 +138,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
|
||||
}
|
||||
|
||||
@@ -154,8 +150,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(
|
||||
@@ -175,7 +171,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 = [serial_number, binding_number];
|
||||
let private_attributes = vec![serial_number, binding_number];
|
||||
let blinded_message = compute_kappa(
|
||||
params,
|
||||
verification_key,
|
||||
@@ -189,8 +185,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,
|
||||
@@ -225,10 +221,7 @@ 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;
|
||||
}
|
||||
|
||||
// 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() {
|
||||
if vk.alpha != *dkg_values.last().unwrap() {
|
||||
return false;
|
||||
}
|
||||
if dkg_values
|
||||
@@ -256,7 +249,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()
|
||||
@@ -279,7 +272,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
|
||||
@@ -298,14 +291,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();
|
||||
|
||||
@@ -327,11 +320,10 @@ mod tests {
|
||||
#[test]
|
||||
fn vk_pairing() {
|
||||
let params = setup(2).unwrap();
|
||||
let keypair = keygen(¶ms);
|
||||
let vk = keypair.verification_key();
|
||||
let vk = keygen(¶ms).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]
|
||||
@@ -348,10 +340,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,7 +1,6 @@
|
||||
// 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,
|
||||
@@ -13,14 +12,14 @@ fn keygen() -> Result<(), CoconutError> {
|
||||
let params = setup(5)?;
|
||||
let node_indices = vec![15u64, 248, 33521];
|
||||
|
||||
random_scalars_refs!(public_attributes, params, 2);
|
||||
let public_attributes = params.n_random_scalars(2);
|
||||
|
||||
// generate_keys
|
||||
let coconut_keypairs = ttp_keygen(¶ms, 2, 3)?;
|
||||
|
||||
let verification_keys: Vec<VerificationKey> = coconut_keypairs
|
||||
.iter()
|
||||
.map(|keypair| keypair.verification_key().clone())
|
||||
.map(|keypair| keypair.verification_key())
|
||||
.collect();
|
||||
|
||||
// aggregate verification keys
|
||||
@@ -51,14 +50,14 @@ fn dkg() -> Result<(), CoconutError> {
|
||||
let params = setup(5)?;
|
||||
let node_indices = vec![15u64, 248, 33521];
|
||||
|
||||
random_scalars_refs!(public_attributes, params, 2);
|
||||
let public_attributes = params.n_random_scalars(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().clone())
|
||||
.map(|keypair| keypair.verification_key())
|
||||
.collect();
|
||||
|
||||
// aggregate verification keys
|
||||
|
||||
@@ -5,17 +5,15 @@ 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: &[&PublicAttribute],
|
||||
public_attributes: &Vec<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) =
|
||||
@@ -23,7 +21,7 @@ pub fn theta_from_keys_and_attributes(
|
||||
|
||||
let verification_keys: Vec<VerificationKey> = coconut_keypairs
|
||||
.iter()
|
||||
.map(|keypair| keypair.verification_key().clone())
|
||||
.map(|keypair| keypair.verification_key())
|
||||
.collect();
|
||||
|
||||
// aggregate verification keys
|
||||
@@ -35,7 +33,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,
|
||||
)?;
|
||||
@@ -51,7 +49,7 @@ pub fn theta_from_keys_and_attributes(
|
||||
.map(|(idx, s, vk)| {
|
||||
(
|
||||
*idx,
|
||||
s.unblind_and_verify(
|
||||
s.unblind(
|
||||
params,
|
||||
vk,
|
||||
&private_attributes,
|
||||
@@ -83,15 +81,13 @@ 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![];
|
||||
@@ -170,14 +166,3 @@ 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,13 +1,4 @@
|
||||
// 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
|
||||
@@ -23,67 +14,9 @@ where
|
||||
Self: Bytable,
|
||||
{
|
||||
fn try_from_bs58<S: AsRef<str>>(x: S) -> Result<Self, CoconutError> {
|
||||
let bs58_decoded = &bs58::decode(x.as_ref()).into_vec()?;
|
||||
Self::try_from_byte_slice(bs58_decoded)
|
||||
Self::try_from_byte_slice(&bs58::decode(x.as_ref()).into_vec().unwrap())
|
||||
}
|
||||
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,7 +34,6 @@ 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
|
||||
@@ -149,8 +148,6 @@ 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 = { workspace = true, features = ["codec"] }
|
||||
tokio-util = { version = "0.7.4", features = ["codec"] }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
nym-sphinx-types = { path = "../types", features = ["sphinx", "outfox"] }
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
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,7 +3,6 @@ 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,14 +3,13 @@ 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 = { 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
|
||||
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
|
||||
# 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,7 +3,6 @@ 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,7 +5,6 @@
|
||||
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,7 +2,6 @@
|
||||
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
|
||||
|
||||
@@ -21,4 +20,4 @@ getrandom = { version = "0.2", features = ["js"] }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
json = ["serde_json"]
|
||||
json = ["serde_json"]
|
||||
@@ -494,13 +494,13 @@ impl Drop for TaskClient {
|
||||
fn drop(&mut self) {
|
||||
if !self.mode.should_signal_on_drop() {
|
||||
self.log(
|
||||
Level::Trace,
|
||||
"the task client is getting dropped but inststructed to not signal: this is expected during client shutdown",
|
||||
Level::Debug,
|
||||
"the task client is getting dropped: this is expected during client shutdown",
|
||||
);
|
||||
return;
|
||||
} else {
|
||||
self.log(
|
||||
Level::Debug,
|
||||
Level::Info,
|
||||
"the task client is getting dropped: this is expected during client shutdown",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ description = "Nym common types"
|
||||
authors.workspace = true
|
||||
edition = "2021"
|
||||
rust-version = "1.58"
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
base64 = "0.21.4"
|
||||
|
||||
@@ -3,7 +3,6 @@ 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
|
||||
|
||||
@@ -18,4 +17,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,7 +3,6 @@ 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
|
||||
|
||||
|
||||
@@ -127,7 +127,26 @@ pub fn query(deps: Deps<'_>, _env: Env, msg: QueryMsg) -> Result<QueryResponse,
|
||||
}
|
||||
|
||||
#[entry_point]
|
||||
pub fn migrate(_deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
|
||||
pub fn migrate(deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
|
||||
let mut current_epoch = CURRENT_EPOCH.load(deps.storage)?;
|
||||
current_epoch
|
||||
.time_configuration
|
||||
.public_key_submission_time_secs = 1200;
|
||||
current_epoch.time_configuration.dealing_exchange_time_secs = 1200;
|
||||
current_epoch
|
||||
.time_configuration
|
||||
.verification_key_submission_time_secs = 600;
|
||||
current_epoch
|
||||
.time_configuration
|
||||
.verification_key_validation_time_secs = 600;
|
||||
current_epoch
|
||||
.time_configuration
|
||||
.verification_key_finalization_time_secs = 600;
|
||||
current_epoch.time_configuration.in_progress_time_secs = 60 * 60 * 24 * 365 * 10;
|
||||
|
||||
CURRENT_EPOCH.save(deps.storage, ¤t_epoch)?;
|
||||
|
||||
//
|
||||
Ok(Default::default())
|
||||
}
|
||||
|
||||
|
||||
@@ -25,9 +25,9 @@ type DealingKey<'a> = &'a Addr;
|
||||
// if TOTAL_DEALINGS is modified to anything other then current value (5), this part will also need
|
||||
// to be modified
|
||||
pub(crate) const DEALINGS_BYTES: [Map<'_, DealingKey<'_>, ContractSafeBytes>; TOTAL_DEALINGS] = [
|
||||
Map::new("dbyt1"),
|
||||
Map::new("dbyt2"),
|
||||
Map::new("dbyt3"),
|
||||
Map::new("dbyt4"),
|
||||
Map::new("dbyt5"),
|
||||
Map::new("dbyt1-tmp2"),
|
||||
Map::new("dbyt2-tmp2"),
|
||||
Map::new("dbyt3-tmp2"),
|
||||
Map::new("dbyt4-tmp2"),
|
||||
Map::new("dbyt5-tmp2"),
|
||||
];
|
||||
|
||||
@@ -104,16 +104,8 @@ 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",
|
||||
"BSD-2-Clause",
|
||||
"BSD-3-Clause",
|
||||
"ISC",
|
||||
"0BSD",
|
||||
"MPL-2.0",
|
||||
"CC0-1.0",
|
||||
"Unicode-DFS-2016",
|
||||
"OpenSSL",
|
||||
#"MIT",
|
||||
#"Apache-2.0",
|
||||
]
|
||||
# List of explicitly disallowed licenses
|
||||
# See https://spdx.org/licenses/ for list of possible licenses
|
||||
@@ -151,22 +143,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)
|
||||
- [Simple Service Provider](tutorials/simple-service-provider/simple-service-provider.md)
|
||||
- [[DEPRECATED] 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,12 +59,11 @@
|
||||
- [Building Your Service Provider](tutorials/simple-service-provider/service-provider.md)
|
||||
- [Sending a Message Through the Mixnet](tutorials/simple-service-provider/sending-message.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))
|
||||
# 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://rpc.sandbox.nymtech.net";
|
||||
pub const DEFAULT_VALIDATOR_RPC: &str = "https://sandbox-validator1.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://rpc.sandbox.nymtech.net"
|
||||
NYXD="https://sandbox-validator1.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://rpc.sandbox.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://sandbox-validator1.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://rpc.sandbox.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://sandbox-validator1.nymtech.net --mnemonic "<any valid sandbox mnemonic>" --amount 100 --recovery-dir <a-path>`
|
||||
|
||||
Run the socks5 client:
|
||||
|
||||
|
||||
@@ -60,9 +60,6 @@ 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 [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 **new [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 - check out the [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 - make sure to check out the **new [TS SDK Handbook](https://sdk.nymtech.net/)** !
|
||||
|
||||
## Popular pages
|
||||
**Network Architecture:**
|
||||
|
||||
@@ -17,11 +17,7 @@
|
||||
- [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,10 +61,7 @@ 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](./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`.
|
||||
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`.
|
||||
|
||||
See the options:
|
||||
|
||||
|
||||
@@ -14,6 +14,107 @@ For example `./target/debug/nym-network-requester --no-banner build-info --outpu
|
||||
{"binary_name":"nym-network-requester","build_timestamp":"2023-07-24T15:38:37.00657Z","build_version":"1.1.23","commit_sha":"c70149400206dce24cf20babb1e64f22202672dd","commit_timestamp":"2023-07-24T14:45:45Z","commit_branch":"feature/simplify-cli-parsing","rustc_version":"1.71.0","rustc_channel":"stable","cargo_profile":"debug"}
|
||||
```
|
||||
|
||||
## Upgrading your node
|
||||
|
||||
> The process is the similar for Mix Node, Gateway and Network Requester. In the following steps we use a placeholder `<NODE>` in the commands, please change it for the binary name you want to upgrade (ie `nym-mixnode`). Any particularities for the given type of node are included.
|
||||
|
||||
Upgrading your node is a two-step process:
|
||||
|
||||
1. Updating the binary and `~/.nym/<NODE>/<YOUR_ID>/config/config.toml` on your VPS
|
||||
2. Updating the node information in the [mixnet smart contract](https://nymtech.net/docs/nyx/mixnet-contract.html). **This is the information that is present on the [mixnet explorer](https://explorer.nymtech.net)**.
|
||||
|
||||
### Step 1: Upgrading your binary
|
||||
Follow these steps to upgrade your Node binary and update its config file:
|
||||
* Pause your node process.
|
||||
- if you see the terminal window with your node, press `ctrl + c`
|
||||
- if you run it as `systemd` service, run: `systemctl stop <NODE>.service`
|
||||
* Replace the existing `<NODE>` binary with the newest binary (which you can either [compile yourself](https://nymtech.net/docs/binaries/building-nym.html) or grab from our [releases page](https://github.com/nymtech/nym/releases)).
|
||||
* Re-run `init` with the same values as you used initially for your `<NODE>` ([Mix Node](./mix-node-setup.md#initialising-your-mix-node), [Gateway](./gateway-setup.md#initialising-your-gateway)) . **This will just update the config file, it will not overwrite existing keys**.
|
||||
* Restart your node process with the new binary:
|
||||
- if your node is *not automated*, just `run` your `<NODE>` with `./<NODE> run --id <ID>`. Here are exact guidelines for [Mix Node](./mix-node-setup.md#running-your-mix-node) and [Gateway](./gateway-setup.md#running-your-gateway).
|
||||
- if you *automated* your node with systemd (recommended) run:
|
||||
```sh
|
||||
systemctl daemon-reload # to pickup the new unit file
|
||||
systemctl start <NODE>.service
|
||||
journalctl -f -u <NODE>.service # to monitor log of you node
|
||||
```
|
||||
|
||||
If these steps are too difficult and you prefer to just run a script, you can use [ExploreNYM script](https://github.com/ExploreNYM/bash-tool) or one done by [Nym developers](https://gist.github.com/tommyv1987/4dca7cc175b70742c9ecb3d072eb8539).
|
||||
|
||||
> In case of a Network Requester this is all, the following step is only for Mix Nodes and Gateways.
|
||||
|
||||
### Step 2: Updating your node information in the smart contract
|
||||
Follow these steps to update the information about your `<NODE>` which is publicly available from the [`nym-api`](https://validator.nymtech.net/api/swagger/index.html) and information displayed on the [Mixnet explorer](https://explorer.nymtech.net).
|
||||
|
||||
You can either do this graphically via the Desktop Wallet, or the CLI.
|
||||
|
||||
### Updating node information via the Desktop Wallet (recommended)
|
||||
* Navigate to the `Bonding` page and click the `Node Settings` link in the top right corner:
|
||||
|
||||

|
||||
|
||||
* Update the fields in the `Node Settings` page (usually the field `Version` is the only one to change) and click `Submit changes to the blockchain`.
|
||||
|
||||

|
||||
|
||||
### Updating node information via the CLI
|
||||
If you want to bond your `<NODE>` via the CLI, then check out the [relevant section in the Nym CLI](https://nymtech.net/docs/tools/nym-cli.html#upgrade-a-mix-node) docs.
|
||||
|
||||
|
||||
### Upgrading Network Requester to >= v1.1.10 from <v1.1.9
|
||||
|
||||
In the previous version of the network-requester, users were required to run a nym-client along side it to function. As of `v1.1.10`, the network-requester now has a nym client embedded into the binary, so it can run standalone.
|
||||
|
||||
If you are running an existing Network Requester registered with nym-connect, upgrading requires you move your old keys over to the new Network Requester configuration. We suggest following these instructions carefully to ensure a smooth transition.
|
||||
|
||||
Initiate the new Network Requester:
|
||||
|
||||
```sh
|
||||
nym-network-requester init --id <YOUR_ID>
|
||||
```
|
||||
|
||||
Copy the old keys from your client to the network-requester configuration that was created above:
|
||||
|
||||
```sh
|
||||
cp -vr ~/.nym/clients/myoldclient/data/* ~/.nym/service-providers/network-requester/<YOUR_ID>/data
|
||||
```
|
||||
|
||||
Edit the configuration to match what you used on your client. Specifically, edit the configuration file at:
|
||||
|
||||
```sh
|
||||
~/.nym/service-providers/network-requester/<YOUR_ID>/config/config.toml
|
||||
```
|
||||
|
||||
Ensure that the fields `gateway_id`, `gateway_owner`, `gateway_listener` in the new config match those in the old client config at:
|
||||
|
||||
```sh
|
||||
~/.nym/clients/myoldclient/config/config.toml
|
||||
```
|
||||
|
||||
### Upgrading your validator
|
||||
|
||||
Upgrading from `v0.31.1` -> `v0.32.0` process is fairly simple. Grab the `v0.32.0` release tarball from the [`nyxd` releases page](https://github.com/nymtech/nyxd/releases), and untar it. Inside are two files:
|
||||
|
||||
- the new validator (`nyxd`) v0.32.0
|
||||
- the new wasmvm (it depends on your platform, but most common filename is `libwasmvm.x86_64.so`)
|
||||
|
||||
Wait for the upgrade height to be reached and the chain to halt awaiting upgrade, then:
|
||||
|
||||
* copy `libwasmvm.x86_64.so` to the default LD_LIBRARY_PATH on your system (on Ubuntu 20.04 this is `/lib/x86_64-linux-gnu/`) replacing your existing file with the same name.
|
||||
* swap in your new `nyxd` binary and restart.
|
||||
|
||||
You can also use something like [Cosmovisor](https://github.com/cosmos/cosmos-sdk/tree/main/tools/cosmovisor) - grab the relevant information from the current upgrade proposal [here](https://nym.explorers.guru/proposal/9).
|
||||
|
||||
Note: Cosmovisor will swap the `nyxd` binary, but you'll need to already have the `libwasmvm.x86_64.so` in place.
|
||||
|
||||
#### Common reasons for your validator being jailed
|
||||
|
||||
The most common reason for your validator being jailed is that your validator is out of memory because of bloated syslogs.
|
||||
|
||||
Running the command `df -H` will return the size of the various partitions of your VPS.
|
||||
|
||||
If the `/dev/sda` partition is almost full, try pruning some of the `.gz` syslog archives and restart your validator process.
|
||||
|
||||
|
||||
## Run Web Secure Socket (WSS) on Gateway
|
||||
|
||||
@@ -25,14 +126,14 @@ These steps are for an operator who is setting up a [Gateway](gateway-setup.md)
|
||||
|
||||
1. New flags will need to be added to the `init` and `run` command. The `--host` option should be replaced with these flags:
|
||||
|
||||
- `--listening-address`: The IP address which is used for receiving sphinx packets and listening to client data.
|
||||
- `--public-ips`: A comma separated list of IP’s that are announced to the `nym-api`. In the most cases `--public-ips` **is the address used for bonding.**
|
||||
- `--listening-address`: The IP address which is used for receiving sphinx packets and listening to client data.
|
||||
- `--public-ips`: A comma separated list of IP’s that are announced to the `nym-api`. In the most cases `--public-ips` **is the address used for bonding.**
|
||||
|
||||
```sh
|
||||
--listening-address 0.0.0.0 --public-ips "$(curl -4 https://ifconfig.me)"
|
||||
```
|
||||
|
||||
- `--hostname` (optional): This flag is required if the operator wishes to run WSS. It can be something like `mainnet-gateway2.nymtech.net`.
|
||||
- `--hostname` (optional): This flag is required if the operator wishes to run WSS. It can be something like `mainnet-gateway2.nymtech.net`.
|
||||
|
||||
2. Make sure to enable all necessary [ports](maintenance.md#configure-your-firewall) on the Gateway:
|
||||
|
||||
@@ -42,7 +143,7 @@ sudo ufw allow 1789,1790,8000,9000,9001,22/tcp, 9001/tcp
|
||||
|
||||
The Gateway will then be accessible on something like: *http://85.159.211.99:8080/api/v1/swagger/index.html*
|
||||
|
||||
Are you seeing something like: *this node attempted to announce an invalid public address: 0.0.0.0.*?
|
||||
Are you seeing something like: *this node attempted to announce an invalid public address: 0.0.0.0.*?
|
||||
|
||||
Please modify `[host.public_ips]` section of your config file stored as `~/.nym/gateways/<ID>/config/config.toml`.
|
||||
|
||||
@@ -92,7 +193,7 @@ curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo
|
||||
apt update
|
||||
apt install caddy
|
||||
|
||||
systemctl enable caddy.service
|
||||
systemctl enable caddy.service
|
||||
|
||||
cd /etc/caddy
|
||||
|
||||
@@ -102,7 +203,7 @@ if [ -f Caddyfile ]; then
|
||||
rm -f Caddyfile
|
||||
fi
|
||||
|
||||
cat <<EOF >> Caddyfile
|
||||
cat <<EOF >> Caddyfile
|
||||
${host}:${port_value} {
|
||||
@websockets {
|
||||
header Connection *Upgrade*
|
||||
@@ -191,9 +292,9 @@ nohup ./<NODE> run --id <YOUR_ID> # where `<YOUR_ID>` is the id you set during t
|
||||
|
||||
#### tmux
|
||||
|
||||
One way is to use `tmux` shell on top of your current VPS terminal. Tmux is a terminal multiplexer, it allows you to create several terminal windows and panes from a single terminal. Processes started in `tmux` keep running after closing the terminal as long as the given `tmux` window was not terminated.
|
||||
One way is to use `tmux` shell on top of your current VPS terminal. Tmux is a terminal multiplexer, it allows you to create several terminal windows and panes from a single terminal. Processes started in `tmux` keep running after closing the terminal as long as the given `tmux` window was not terminated.
|
||||
|
||||
Use the following command to get `tmux`.
|
||||
Use the following command to get `tmux`.
|
||||
|
||||
Platform|Install Command
|
||||
---|---
|
||||
@@ -204,15 +305,15 @@ RHEL or CentOS|`yum install tmux`
|
||||
macOS (using Homebrew|`brew install tmux`
|
||||
macOS (using MacPorts)|`port install tmux`
|
||||
openSUSE|`zypper install tmux`
|
||||
|
||||
In case it didn't work for your distribution, see how to build `tmux` from [version control](https://github.com/tmux/tmux#from-version-control).
|
||||
|
||||
In case it didn't work for your distribution, see how to build `tmux` from [version control](https://github.com/tmux/tmux#from-version-control).
|
||||
|
||||
**Running tmux**
|
||||
|
||||
Now you have installed tmux on your VPS, let's run a Mix Node on tmux, which allows you to detach your terminal and let your `<NODE>` run on its own on the VPS.
|
||||
No when you installed tmux on your VPS, let's run a Mix Node on tmux, which allows you to detach your terminal and let your `<NODE>` run on its own on the VPS.
|
||||
|
||||
* Pause your `<NODE>`
|
||||
* Start tmux with the command
|
||||
* Start tmux with the command
|
||||
```sh
|
||||
tmux
|
||||
```
|
||||
@@ -230,7 +331,7 @@ tmux attach-session
|
||||
|
||||
#### systemd
|
||||
|
||||
To automate with `systemd` use this init service file and follow the steps below.
|
||||
To automate with `systemd` use this init service file and follow the steps below.
|
||||
|
||||
##### For Mix Node
|
||||
|
||||
@@ -298,47 +399,24 @@ WantedBy=multi-user.target
|
||||
```
|
||||
* Put the above file onto your system at `/etc/systemd/system/nym-network-requester.service` and follow the [next steps](maintenance.md#following-steps-for-nym-nodes-running-as-systemd-service).
|
||||
|
||||
##### For Nymvisor
|
||||
> Since you're running your node via a Nymvisor instance, as well as creating a Nymvisor `.service` file, you will also want to **stop any previous node automation process you already have running**.
|
||||
|
||||
```
|
||||
[Unit]
|
||||
Description=Nymvisor <VERSION>
|
||||
StartLimitInterval=350
|
||||
StartLimitBurst=10
|
||||
|
||||
[Service]
|
||||
User=nym # replace this with whatever user you wish
|
||||
LimitNOFILE=65536
|
||||
ExecStart=/home/<USER>/<PATH>/nymvisor run run --id <NODE_ID>
|
||||
KillSignal=SIGINT
|
||||
Restart=on-failure
|
||||
RestartSec=30
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
* Put the above file onto your system at `/etc/systemd/system/nymvisor.service` and follow the [next steps](maintenance.md#following-steps-for-nym-nodes-running-as-systemd-service).
|
||||
|
||||
#### Following steps for Nym nodes running as `systemd` service
|
||||
|
||||
Change the `<PATH>` in `ExecStart` to point at your `<NODE>` binary (`nym-mixnode`, `nym-gateway` or `nym-network-requester`), and the `<USER>` so it is the user you are running as.
|
||||
|
||||
Example: If you have built nym in the `$HOME` directory on your server, your username is `jetpanther`, and node `<ID>` is `puma`, then the `ExecStart` line (command) in the script located in `/etc/systemd/system/nym-mixnode.service` for Nym Mixnode might look like this:
|
||||
|
||||
`ExecStart=/home/jetpanther/nym/target/release/nym-mixnode run --id puma`.
|
||||
`ExecStart=/home/jetpanther/nym/target/release/nym-mixnode run --id puma`.
|
||||
|
||||
Basically, you want the full `/<PATH>/<TO>/nym-mixnode run --id <WHATEVER-YOUR-NODE-ID-IS>`. If you are unsure about your `/<PATH>/<TO>/<NODE>`, then `cd` to your directory where you run your `<NODE>` from and run `pwd` command which returns the full path for you.
|
||||
|
||||
Once done, save the script and follow these steps:
|
||||
|
||||
```sh
|
||||
systemctl daemon-reload
|
||||
systemctl daemon-reload
|
||||
# to pickup the new unit file
|
||||
```
|
||||
|
||||
Enable the newly created service:
|
||||
Enable the newly created service:
|
||||
|
||||
```sh
|
||||
# for Mix Node
|
||||
@@ -349,9 +427,6 @@ systemctl enable nym-gateway.service
|
||||
|
||||
# for Network Requester
|
||||
systemctl enable nym-network-requester.service
|
||||
|
||||
# for Nymvisor
|
||||
systemctl enable nymvisor.service
|
||||
```
|
||||
|
||||
Start your `<NODE>` as a `systemd` service:
|
||||
@@ -365,9 +440,6 @@ service nym-gateway start
|
||||
|
||||
# for Network Requester
|
||||
service nym-network-requester.service
|
||||
|
||||
# for Nymvisor
|
||||
service nymvisor.service start
|
||||
```
|
||||
|
||||
This will cause your `<NODE>` to start at system boot time. If you restart your machine, your `<NODE>` will come back up automatically.
|
||||
@@ -427,38 +499,6 @@ systemctl start nymd # to actually start the service
|
||||
journalctl -f -u nymd # to monitor system logs showing the service start
|
||||
```
|
||||
|
||||
##### For Nym API
|
||||
|
||||
Below is a `systemd` unit file to place at `/etc/systemd/system/nym-api.service` to automate your API instance:
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=NymAPI
|
||||
StartLimitInterval=350
|
||||
StartLimitBurst=10
|
||||
|
||||
[Service]
|
||||
User=<USER> # change to your user
|
||||
Type=simple
|
||||
ExecStart=/home/<USER>/<PATH_TO_BINARY>/nym-api start # change to correct path
|
||||
Restart=on-failure
|
||||
RestartSec=30
|
||||
LimitNOFILE=infinity
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
Proceed to start it with:
|
||||
|
||||
```sh
|
||||
systemctl daemon-reload # to pickup the new unit file
|
||||
systemctl enable nym-api # to enable the service
|
||||
systemctl start nym-api # to actually start the service
|
||||
journalctl -f -u nym-api # to monitor system logs showing the service start
|
||||
```
|
||||
|
||||
|
||||
### Setting the ulimit
|
||||
|
||||
Linux machines limit how many open files a user is allowed to have. This is called a `ulimit`.
|
||||
@@ -535,7 +575,7 @@ In case you chose tmux option for Mix Node automation, see your `ulimit` list by
|
||||
ulimit -a
|
||||
|
||||
# watch for the output line -n
|
||||
-n: file descriptors 1024
|
||||
-n: file descriptors 1024
|
||||
```
|
||||
|
||||
You can change it either by running a command:
|
||||
@@ -582,14 +622,14 @@ scp -r -3 <SOURCE_USER_NAME>@<SOURCE_HOST_ADDRESS>:~/.nym/mixnodes/<YOUR_ID> <TA
|
||||
```
|
||||
* Re-run init (remember that init doesn't overwrite existing keys) to generate a config with the new listening address etc.
|
||||
* Change the node smart contract info via the wallet interface. Otherwise the keys will point to the old IP address in the smart contract, and the node will not be able to be connected, and it will fail up-time checks.
|
||||
* Re-run the node from the new location.
|
||||
* Re-run the node from the new location.
|
||||
|
||||
|
||||
## Virtual IPs and hosting via Google & AWS
|
||||
|
||||
For true internet decentralization we encourage operators to use diverse VPS providers instead of the largest companies offering such services. If for some reasons you have already running AWS or Google and want to setup a `<NODE>` there, please read the following.
|
||||
|
||||
On some services (AWS, Google, etc) the machine's available bind address is not the same as the public IP address. In this case, bind `--host` to the local machine address returned by `$(curl -4 https://ifconfig.me)`, but that may not the public IP address to bond your `<NODE>` in the wallet.
|
||||
On some services (AWS, Google, etc) the machine's available bind address is not the same as the public IP address. In this case, bind `--host` to the local machine address returned by `$(curl -4 https://ifconfig.me)`, but that may not the public IP address to bond your `<NODE>` in the wallet.
|
||||
|
||||
You can run `ifconfig` command. For example, on a Google machine, you may see the following output:
|
||||
|
||||
@@ -601,7 +641,7 @@ ens4: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1460
|
||||
|
||||
The `ens4` interface has the IP `10.126.5.7`. But this isn't the public IP of the machine, it's the IP of the machine on Google's internal network. Google uses virtual routing, so the public IP of this machine is something else, maybe `36.68.243.18`.
|
||||
|
||||
To find the right IP configuration, contact your VPS provider for support to find the right public IP and use it to bond your `<NODE>` with the `nym-api` via Nym wallet.
|
||||
To find the right IP configuration, contact your VPS provider for support to find the right public IP and use it to bond your `<NODE>` with the `nym-api` via Nym wallet.
|
||||
|
||||
On self-hosted machine it's a bit more tricky. In that case as an operator you must be sure that your ISP allows for public IPv4 and IPv6 and then it may be a bit of playing around to find the right configuration. One way may be to bind your binary with the `--host` flag to local address `127.0.0.1` and run `echo "$(curl -4 https://ifconfig.me)"` to get a public address which you use to bond your Mix Node to `nym-api` via Nym wallet.
|
||||
|
||||
@@ -650,7 +690,7 @@ Query Response:
|
||||
|
||||
### Validator: Installing and configuring nginx for HTTPS
|
||||
#### Setup
|
||||
[Nginx](https://www.nginx.com/resources/glossary/nginx) is an open source software used for operating high-performance web servers. It allows us to set up reverse proxying on our validator server to improve performance and security.
|
||||
[Nginx](https://www.nginx.com/resources/glossary/nginx/#:~:text=NGINX%20is%20open%20source%20software,%2C%20media%20streaming%2C%20and%20more.&text=In%20addition%20to%20its%20HTTP,%2C%20TCP%2C%20and%20UDP%20servers.) is an open source software used for operating high-performance web servers. It allows us to set up reverse proxying on our validator server to improve performance and security.
|
||||
|
||||
Install `nginx` and allow the 'Nginx Full' rule in your firewall:
|
||||
|
||||
@@ -678,16 +718,15 @@ Which should return:
|
||||
└─2380 nginx: worker process
|
||||
```
|
||||
|
||||
#### Full Node Configuration
|
||||
#### Configuration
|
||||
|
||||
Proxying various full node services through port 80 can then be done by creating a file with the following at `/etc/nginx/sites-enabled/nyxd-webrequests.conf`:
|
||||
Proxying your validator's port `26657` to nginx port `80` can then be done by creating a file with the following at `/etc/nginx/conf.d/validator.conf`:
|
||||
|
||||
```sh
|
||||
### To expose RPC server
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name "<rpc.nyx.yourdomain.tld>";
|
||||
server_name "domain_name";
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:26657;
|
||||
@@ -696,58 +735,20 @@ server {
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
}
|
||||
}
|
||||
|
||||
### To expose Cosmos API server
|
||||
server {
|
||||
server_name "<api.nyx.yourdomain.tld>";
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:1317;
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header Upgrade websocket;
|
||||
proxy_set_header Connection Upgrade;
|
||||
}
|
||||
}
|
||||
|
||||
### To expose GRPC endpoint
|
||||
server {
|
||||
server_name "<grpc.nyx.yourdomain.tld>";
|
||||
location / {
|
||||
grpc_pass 127.0.0.1:9090;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### nym-api Configuration
|
||||
|
||||
```sh
|
||||
### To expose nym-api webserver
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name "<nym-api.nyx.yourdomain.tld>";
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:8000;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Followed by:
|
||||
|
||||
```sh
|
||||
sudo apt install certbot nginx python3
|
||||
certbot --nginx -m <you@yourdomain.com> --agree-tos
|
||||
certbot --nginx -d nym-validator.yourdomain.com -m you@yourdomain.com --agree-tos --noninteractive --redirect
|
||||
```
|
||||
|
||||
```admonish caution title=""
|
||||
If using a VPS running Ubuntu 20: replace `certbot nginx python3` with `python3-certbot-nginx`
|
||||
```
|
||||
|
||||
These commands will get you an https encrypted nginx proxy in front of the various endpoints.
|
||||
These commands will get you an https encrypted nginx proxy in front of the API.
|
||||
|
||||
### Configuring Prometheus metrics (optional)
|
||||
|
||||
@@ -834,3 +835,6 @@ All validator-specific port configuration can be found in `$HOME/.nymd/config/co
|
||||
| 1317 | REST API server endpoint |
|
||||
| 26656 | Listen for incoming peer connections |
|
||||
| 26660 | Listen for Prometheus connections |
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
# Manual Node Upgrade
|
||||
|
||||
> The process here is similar for the Mix Node, Gateway and Network Requester binaries. In the following steps we use a placeholder `<NODE>` in the commands, please change it for the binary name you want to upgrade (e.g.`nym-mixnode`). Any particularities for the given type of node are included.
|
||||
|
||||
Upgrading your node is a two-step process:
|
||||
|
||||
1. Updating the binary and `~/.nym/<NODE>/<YOUR_ID>/config/config.toml` on your VPS
|
||||
2. Updating the node information in the [mixnet smart contract](https://nymtech.net/docs/nyx/mixnet-contract.html). **This is the information that is present on the [mixnet explorer](https://explorer.nymtech.net)**.
|
||||
|
||||
## Step 1: Upgrading your binary
|
||||
Follow these steps to upgrade your Node binary and update its config file:
|
||||
* Pause your node process.
|
||||
- if you see the terminal window with your node, press `ctrl + c`
|
||||
- if you run it as `systemd` service, run: `systemctl stop <NODE>.service`
|
||||
* Replace the existing `<NODE>` binary with the newest binary (which you can either [compile yourself](https://nymtech.net/docs/binaries/building-nym.html) or grab from our [releases page](https://github.com/nymtech/nym/releases)).
|
||||
* Re-run `init` with the same values as you used initially for your `<NODE>` ([Mix Node](./mix-node-setup.md#initialising-your-mix-node), [Gateway](./gateway-setup.md#initialising-your-gateway)) . **This will just update the config file, it will not overwrite existing keys**.
|
||||
* Restart your node process with the new binary:
|
||||
- if your node is *not automated*, just `run` your `<NODE>` with `./<NODE> run --id <ID>`. Here are exact guidelines for [Mix Node](./mix-node-setup.md#running-your-mix-node) and [Gateway](./gateway-setup.md#running-your-gateway).
|
||||
- if you *automated* your node with systemd (recommended) run:
|
||||
```sh
|
||||
systemctl daemon-reload # to pickup the new unit file
|
||||
systemctl start <NODE>.service
|
||||
journalctl -f -u <NODE>.service # to monitor log of you node
|
||||
```
|
||||
|
||||
If these steps are too difficult and you prefer to just run a script, you can use [ExploreNYM script](https://github.com/ExploreNYM/bash-tool) or one done by [Nym developers](https://gist.github.com/tommyv1987/4dca7cc175b70742c9ecb3d072eb8539).
|
||||
|
||||
> In case of a Network Requester this is all, the following step is only for Mix Nodes and Gateways.
|
||||
|
||||
## Step 2: Updating your node information in the smart contract
|
||||
Follow these steps to update the information about your `<NODE>` which is publicly available from the [`nym-api`](https://validator.nymtech.net/api/swagger/index.html) and information displayed on the [Mixnet explorer](https://explorer.nymtech.net).
|
||||
|
||||
You can either do this graphically via the Desktop Wallet, or the CLI.
|
||||
|
||||
### Updating node information via the Desktop Wallet (recommended)
|
||||
* Navigate to the `Bonding` page and click the `Node Settings` link in the top right corner:
|
||||
|
||||

|
||||
|
||||
* Update the fields in the `Node Settings` page (usually the field `Version` is the only one to change) and click `Submit changes to the blockchain`.
|
||||
|
||||

|
||||
|
||||
### Updating node information via the CLI
|
||||
If you want to bond your `<NODE>` via the CLI, then check out the [relevant section in the Nym CLI](https://nymtech.net/docs/tools/nym-cli.html#upgrade-a-mix-node) docs.
|
||||
|
||||
|
||||
## Upgrading Network Requester to >= v1.1.10 from <v1.1.9
|
||||
|
||||
In the previous version of the network-requester, users were required to run a nym-client along side it to function. As of `v1.1.10`, the network-requester now has a nym client embedded into the binary, so it can run standalone.
|
||||
|
||||
If you are running an existing Network Requester registered with nym-connect, upgrading requires you move your old keys over to the new Network Requester configuration. We suggest following these instructions carefully to ensure a smooth transition.
|
||||
|
||||
Initiate the new Network Requester:
|
||||
|
||||
```sh
|
||||
nym-network-requester init --id <YOUR_ID>
|
||||
```
|
||||
|
||||
Copy the old keys from your client to the network-requester configuration that was created above:
|
||||
|
||||
```sh
|
||||
cp -vr ~/.nym/clients/myoldclient/data/* ~/.nym/service-providers/network-requester/<YOUR_ID>/data
|
||||
```
|
||||
|
||||
Edit the configuration to match what you used on your client. Specifically, edit the configuration file at:
|
||||
|
||||
```sh
|
||||
~/.nym/service-providers/network-requester/<YOUR_ID>/config/config.toml
|
||||
```
|
||||
|
||||
Ensure that the fields `gateway_id`, `gateway_owner`, `gateway_listener` in the new config match those in the old client config at:
|
||||
|
||||
```sh
|
||||
~/.nym/clients/myoldclient/config/config.toml
|
||||
```
|
||||
|
||||
## Upgrading your validator
|
||||
|
||||
Upgrading from `v0.31.1` -> `v0.32.0` process is fairly simple. Grab the `v0.32.0` release tarball from the [`nyxd` releases page](https://github.com/nymtech/nyxd/releases), and untar it. Inside are two files:
|
||||
|
||||
- the new validator (`nyxd`) v0.32.0
|
||||
- the new wasmvm (it depends on your platform, but most common filename is `libwasmvm.x86_64.so`)
|
||||
|
||||
Wait for the upgrade height to be reached and the chain to halt awaiting upgrade, then:
|
||||
|
||||
* copy `libwasmvm.x86_64.so` to the default LD_LIBRARY_PATH on your system (on Ubuntu 20.04 this is `/lib/x86_64-linux-gnu/`) replacing your existing file with the same name.
|
||||
* swap in your new `nyxd` binary and restart.
|
||||
|
||||
You can also use something like [Cosmovisor](https://github.com/cosmos/cosmos-sdk/tree/main/tools/cosmovisor) - grab the relevant information from the current upgrade proposal [here](https://nym.explorers.guru/proposal/9).
|
||||
|
||||
Note: Cosmovisor will swap the `nyxd` binary, but you'll need to already have the `libwasmvm.x86_64.so` in place.
|
||||
|
||||
### Common reasons for your validator being jailed
|
||||
|
||||
The most common reason for your validator being jailed is that your validator is out of memory because of bloated syslogs.
|
||||
|
||||
Running the command `df -H` will return the size of the various partitions of your VPS.
|
||||
|
||||
If the `/dev/sda` partition is almost full, try pruning some of the `.gz` syslog archives and restart your validator process.
|
||||
|
||||
@@ -68,7 +68,7 @@ Initialise your Mix Node with the following command, replacing the value of `--i
|
||||
```
|
||||
./nym-mixnode init --id <YOUR_ID> --host $(curl -4 https://ifconfig.me)
|
||||
```
|
||||
If `<YOUR_ID>` was `my-node`, the output will look like this:
|
||||
If `<YOUR_ID>` was `my-node`, the output shall look like like this:
|
||||
|
||||
~~~admonish example collapsible=true title="Console output"
|
||||
```
|
||||
|
||||
@@ -1,182 +0,0 @@
|
||||
# Nym API Setup
|
||||
|
||||
[//]: # (> The nym-api binary was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. You can build just the API with `cargo build --release --bin nym-api`.)
|
||||
|
||||
> The `nym-api` binary will be released in the immediate future - we're releasing this document beforehand so that Validators have information as soon as possible and get an idea of what to expect. This doc will be expanded over time as we release the API binary itself as well as start enabling functionality.
|
||||
>
|
||||
> You can build the API with `cargo build --release --bin nym-api`.
|
||||
|
||||
> Any syntax in `<>` brackets is a user's unique variable. Exchange with a corresponding name without the `<>` brackets.
|
||||
|
||||
## What is the Nym API?
|
||||
The Nym API is a binary that will be operated by the Nyx validator set. This binary can be run in several different modes, and has two main bits of functionality:
|
||||
* network monitoring (calculating the routing score of Mixnet nodes)
|
||||
* generation and validation of [zk-Nyms](https://blog.nymtech.net/zk-nyms-are-here-a-major-milestone-towards-a-market-ready-mixnet-a3470c9ab10a), our implementation of the Coconut Selective Disclosure Credential Scheme.
|
||||
|
||||
This is important for both the proper decentralisation of the network uptime calculation and, more pressingly, enabling the NymVPN to utilise privacy preserving payments.
|
||||
|
||||
The process of enabling these different aspects of the system will take time. At the moment, Nym API operators will only have to run the binary in a minimal 'caching' mode in order to get used to maintaining an additional process running alongside a full node.
|
||||
|
||||
```admonish warning
|
||||
It is highly recommended to run `nym-api` alongside a full node since you will be exposing HTTP port(s) to the Internet. We also observed degradation in p2p and block signing operations when `nym-api` was run alongside a signing validator.
|
||||
```
|
||||
|
||||
### Rewards
|
||||
Operators of Nym API will be rewarded for performing the extra work of taking part in credential generation. These rewards will be calculated **separately** from rewards for block production.
|
||||
|
||||
Rewards for credential signing will be calculated hourly, with API operators receiving a proportional amount of the reward pool (333NYM per hour / 237,600 NYM per month), proportional to the percentage of credentials they have signed.
|
||||
|
||||
### (Coming Soon) Machine Specs
|
||||
We are working on load testing currently in order to get good specs for a full node + Nym API setup. Bear in mind that credential signing is primarily CPU-bound.
|
||||
|
||||
### (Coming Soon) Credential Generation
|
||||
Validators that take part in the DKG ceremony will become part of the 'quorum' generating and verifying zk-Nym credentials. These will initially be used for private proof of payment for NymVPN (see our blogposts [here](https://blog.nymtech.net/nymvpn-an-invitation-for-privacy-experts-and-enthusiasts-63644139d09d) and [here](https://blog.nymtech.net/zk-nyms-are-here-a-major-milestone-towards-a-market-ready-mixnet-a3470c9ab10a) for more on this), and in the future will be expanded into more general usecases such as [offline ecash](https://arxiv.org/abs/2303.08221).
|
||||
|
||||
The DKG ceremony will be used to create a subset of existing validators - referred to as the quorum. As outlined above, they will be the ones taking part in the generation and verification of zk-Nym credentials. The size of the 'minimum viable quorum' is 10 - we are aiming for a larger number than this for the initial quorum in order to have some redundancy in the case of a Validator dropping or going offline.
|
||||
|
||||
We will be releasing more detailed step-by-step documentation for involved validators nearer to the ceremony itself, but at a high level it will involve:
|
||||
* the deployment and initialisation of [`group`](https://github.com/nymtech/nym/tree/develop/contracts/multisig/cw4-group) and [`multisig`](https://github.com/nymtech/nym/tree/develop/contracts/multisig) contracts by Nym. Validators that are members of the `group` contract are the only ones that will be able to take part in the ceremony.
|
||||
* the deployment and initialisation of an instance of the [DKG contract](https://github.com/nymtech/nym/tree/develop/contracts/coconut-dkg) by Nym.
|
||||
* Validators will update their `nym-api` configs with the address of the deployed contracts. They will also stop running their API instance in caching only mode, instead switching over run with the `--enabled-credentials-mode`.
|
||||
* From the perspective of operators, this is all they have to do. Under the hood, each `nym-api` instance will then take part in several rounds of key submission, verification, and derivation. This will continue until quorum is acheived. More information on this will be released closer to the time of the ceremony.
|
||||
|
||||
**We will be communicating individually with members of the existing Validator set who have expressed interest in joining the quorum concerning the timing and specifics of the ceremony**.
|
||||
|
||||
## Current version
|
||||
```
|
||||
<!-- cmdrun ../../../../target/release/nym-api --version | grep "Build Version" | cut -b 21-26 -->
|
||||
```
|
||||
|
||||
## Setup and Usage
|
||||
### Viewing command help
|
||||
You can check that your binary is properly compiled with:
|
||||
|
||||
```
|
||||
./nym-api --help
|
||||
```
|
||||
|
||||
Which should return a list of all available commands.
|
||||
|
||||
~~~admonish example collapsible=true title="Console output"
|
||||
```
|
||||
<!-- cmdrun ../../../../target/release/nym-api --help -->
|
||||
```
|
||||
~~~
|
||||
|
||||
You can also check the various arguments required for individual commands with:
|
||||
|
||||
```
|
||||
./nym-api <COMMAND> --help
|
||||
```
|
||||
|
||||
### Initialising your Nym API Instance
|
||||
Initialise your API instance with:
|
||||
|
||||
```
|
||||
./nym-api init
|
||||
```
|
||||
|
||||
You can optionally pass a local identifier for this instance with the `--id` flag. Otherwise the ID of your instance defaults to `default`.
|
||||
|
||||
### Running your Nym API Instance
|
||||
The API binary currently defaults to running in caching mode. You can run your API with:
|
||||
|
||||
```
|
||||
./nym-api run
|
||||
```
|
||||
|
||||
By default the API will be trying to query a running `nyxd` process (either a validator or RPC node) on `localhost:26657`. This value can be modified either via the `--nyxd-validator ` flag on `run`:
|
||||
|
||||
```
|
||||
./nym-api run --nyxd-validator https://rpc.nymtech.net:443
|
||||
```
|
||||
|
||||
> You can also change the value of `local_validator` in the config file found by default in `$HOME/.nym/nym-api/<ID>/config/config.toml`.
|
||||
|
||||
This process is quite noisy, but informative:
|
||||
|
||||
~~~admonish example collapsible=true title="Console output"
|
||||
```
|
||||
Starting nym api...
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch > 🔧 Configured for release.
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > address: 127.0.0.1
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > port: 8000
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > workers: 4
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > max blocking threads: 512
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > ident: Rocket
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > IP header: X-Real-IP
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > limits: bytes = 8KiB, data-form = 2MiB, file = 1MiB, form = 32KiB, json = 1MiB, msgpack = 1MiB, string = 8KiB
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > temp dir: /tmp
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > http/2: true
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > keep-alive: 5s
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > tls: disabled
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > shutdown: ctrlc = true, force = true, signals = [SIGTERM], grace = 2s, mercy = 3s
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > log level: critical
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > cli colors: true
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch > 📬 Routes:
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > (get_registered_names) GET /v1/names
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > (get_mixnodes) GET /v1/mixnodes
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > (get_gateways) GET /v1/gateways
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > (get_services) GET /v1/services
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > GET /v1/openapi.json
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > (get_full_circulating_supply) GET /v1/circulating-supply
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > (get_current_epoch) GET /v1/epoch/current
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > (get_active_set) GET /v1/mixnodes/active
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > (get_mixnodes_detailed) GET /v1/mixnodes/detailed
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > (get_rewarded_set) GET /v1/mixnodes/rewarded
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > (get_gateways_described) GET /v1/gateways/described
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > (get_interval_reward_params) GET /v1/epoch/reward_params
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > (get_blacklisted_mixnodes) GET /v1/mixnodes/blacklisted
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > (get_blacklisted_gateways) GET /v1/gateways/blacklisted
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > (get_total_supply) GET /v1/circulating-supply/total-supply-value
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > (get_circulating_supply) GET /v1/circulating-supply/circulating-supply-value
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > (get_active_set_detailed) GET /v1/mixnodes/active/detailed
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > (get_rewarded_set_detailed) GET /v1/mixnodes/rewarded/detailed
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > GET /cors/<status>
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > GET /swagger/
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > GET /swagger/index.css
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > GET /swagger/index.html
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > GET /swagger/swagger-ui.css
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > GET /swagger/oauth2-redirect.html
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > GET /swagger/swagger-ui-bundle.js
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > GET /swagger/swagger-ui-config.json
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > GET /swagger/swagger-initializer.js
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > GET /swagger/swagger-ui-standalone-preset.js
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > (get_mixnodes_detailed) GET /v1/status/mixnodes/detailed
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > (get_mixnode_inclusion_probabilities) GET /v1/status/mixnodes/inclusion_probability
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > (get_mixnode_status) GET /v1/status/mixnode/<mix_id>/status
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > (get_active_set_detailed) GET /v1/status/mixnodes/active/detailed
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > (get_rewarded_set_detailed) GET /v1/status/mixnodes/rewarded/detailed
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > (get_mixnode_stake_saturation) GET /v1/status/mixnode/<mix_id>/stake-saturation
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > (get_mixnode_inclusion_probability) GET /v1/status/mixnode/<mix_id>/inclusion-probability
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > (network_details) GET /v1/network/details
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > (nym_contracts) GET /v1/network/nym-contracts
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > (nym_contracts_detailed) GET /v1/network/nym-contracts-detailed
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch > 📡 Fairings:
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > Validator Cache Stage (ignite)
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > Circulating Supply Cache Stage (ignite)
|
||||
2023-12-12T14:29:55.800Z INFO rocket::launch::_ > Shield (liftoff, response, singleton)
|
||||
2023-12-12T14:29:55.801Z INFO rocket::launch::_ > CORS (ignite, request, response)
|
||||
2023-12-12T14:29:55.801Z INFO rocket::launch::_ > Node Status Cache (ignite)
|
||||
2023-12-12T14:29:55.801Z INFO rocket::shield::shield > 🛡️ Shield:
|
||||
2023-12-12T14:29:55.801Z INFO rocket::shield::shield::_ > X-Content-Type-Options: nosniff
|
||||
2023-12-12T14:29:55.801Z INFO rocket::shield::shield::_ > X-Frame-Options: SAMEORIGIN
|
||||
2023-12-12T14:29:55.801Z INFO rocket::shield::shield::_ > Permissions-Policy: interest-cohort=()
|
||||
2023-12-12T14:29:55.801Z WARN rocket::launch > 🚀 Rocket has launched from http://127.0.0.1:8000
|
||||
2023-12-12T14:29:56.375Z INFO nym_api::nym_contract_cache::cache::refresher > Updating validator cache. There are 888 mixnodes and 105 gateways
|
||||
2023-12-12T14:29:56.375Z INFO nym_api::node_status_api::cache::refresher > Updating node status cache
|
||||
2023-12-12T14:29:57.359Z INFO nym_api::circulating_supply_api::cache > Updating circulating supply cache
|
||||
2023-12-12T14:29:57.359Z INFO nym_api::circulating_supply_api::cache > the mixmining reserve is now 220198535489690unym
|
||||
2023-12-12T14:29:57.359Z INFO nym_api::circulating_supply_api::cache > the number of tokens still vesting is now 145054386857730unym
|
||||
2023-12-12T14:29:57.359Z INFO nym_api::circulating_supply_api::cache > the circulating supply is now 634747077652580unym
|
||||
2023-12-12T14:30:00.803Z INFO nym_api::support::caching::refresher > node-self-described-data-refresher: refreshing cache state
|
||||
2023-12-12T14:31:56.290Z INFO nym_api::nym_contract_cache::cache::refresher > Updating validator cache. There are 888 mixnodes and 105 gateways
|
||||
2023-12-12T14:31:56.291Z INFO nym_api::node_status_api::cache::refresher > Updating node status cache
|
||||
```
|
||||
~~~
|
||||
|
||||
## Automation
|
||||
You will most likely want to automate your validator restarting if your server reboots. Checkout the [maintenance page](./maintenance.md) for an example `service` file.
|
||||
|
||||
## Exposing web endpoint using HTTPS
|
||||
It is recommended to expose the webserver over HTTPS by using a webserver like Nginx. An example configuration for configuring Nginx is listed [on the maintenance page](maintenance.md#nym-api-configuration)
|
||||
@@ -1,299 +0,0 @@
|
||||
# Automatic Node Upgrade: Nymvisor Setup and Usage
|
||||
|
||||
> The Nymvisor binary was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. You can build just Nymvisor with `cargo build --release --bin nymvisor`.
|
||||
|
||||
> Any syntax in `<>` brackets is a user's unique variable. Exchange with a corresponding name without the `<>` brackets.
|
||||
|
||||
## What is Nymvisor?
|
||||
Nymvisor is a process manager for Nym binaries that monitors the Nym release information for any newly released binaries. If it detects any changes, Nymvisor can automatically download the binary, stop the current binary, switch from the old binary to the new one, and finally restart the underlying process with the new binary.
|
||||
|
||||
In essence, it tries to mirror the behaviour of [Cosmovisor](https://github.com/cosmos/cosmos-sdk/tree/main/tools/cosmovisor), a tool used by Cosmos blockchain operators for managing/automating chain upgrades. Nymvisor, however, introduces some Nym-specific changes since, for example, upgrade information is obtained from our GitHub [releases page](https://github.com/nymtech/nym/releases) instead of (in the case of Cosmos blockchains) governance proposals.
|
||||
|
||||
You can use Nymvisor to automate the upgrades of the following binaries:
|
||||
* `nym-api`
|
||||
* `nym-mixnode`
|
||||
* `nym-gateway`
|
||||
* `nym-network-requester`
|
||||
* `nym-client`
|
||||
* `nym-socks5-client`
|
||||
|
||||
```admonish warning
|
||||
Nymvisor is an early and experimental software. Users should use it at their own risk.
|
||||
```
|
||||
|
||||
## Current version
|
||||
```
|
||||
<!-- cmdrun ../../../../target/release/nymvisor --version | grep "Build Version" | cut -b 21-26 -->
|
||||
```
|
||||
|
||||
## Preliminary steps
|
||||
You need to have at least one Mixnet node / client / Nym API instance already set up on the **same VPS** that you wish to run Nymvisor on.
|
||||
|
||||
> Using Nymvisor presumes your VPS is running an operating system that is compatible with the pre-compiled binaries avaliable on the [Github releases page](https://github.com/nymtech/nym/releases). If you're not, then until we're packaging for a greater variety of operating systems, you're stuck with [manually upgrading your node](manual-upgrade.md).
|
||||
|
||||
## Setup and Usage
|
||||
### Viewing command help
|
||||
You can check that your binaries are properly compiled with:
|
||||
|
||||
```
|
||||
./nymvisor --help
|
||||
```
|
||||
|
||||
Which should return a list of all available commands.
|
||||
|
||||
~~~admonish example collapsible=true title="Console output"
|
||||
```
|
||||
<!-- cmdrun ../../../../target/release/nymvisor --help -->
|
||||
```
|
||||
~~~
|
||||
|
||||
You can also check the various arguments required for individual commands with:
|
||||
|
||||
```
|
||||
./nymvisor <COMMAND> --help
|
||||
```
|
||||
|
||||
### Initialising your Nymvisor Instance
|
||||
> This example will use the Mix Node binary as an example - however replacing `nym-mixnode` with any other supported binary will work the same.
|
||||
|
||||
Initialise your Nymvisor instance with the following command. You must initialise Nymvisor with the binary you wish to add upgrades for:
|
||||
|
||||
```
|
||||
./nymvisor init --daemon-home ~/.nym/<NODE_TYPE>/<NODE_ID> <PATH_TO_NODE_BINARY>
|
||||
```
|
||||
|
||||
Where the value of `--daemon-home` might be `~/.nym/mixnodes/my-node` and `<PATH_TO_NODE_BINARY>` might be `/home/my_user/nym/target/release/nym-mixnode`, or wherever your node binary is located.
|
||||
|
||||
~~~admonish example collapsible=true title="Console output"
|
||||
```
|
||||
<!-- cmdrun ../../../../target/release/nymvisor init --daemon-home ~/.nym/mixnodes/my-node ../../../../target/release/nym-mixnode | tail -20 -->
|
||||
```
|
||||
~~~
|
||||
|
||||
By default this will create config files at `~/.nym/nymvisors/instances/<NODE_TYPE>-default/config/config.toml` as shown in the console output above. For config options look at the different `--flags` available, or the [environment variables](nymvisor-upgrade.md#environment-variables) section below.
|
||||
|
||||
### Running your Nymvisor Instance
|
||||
Nymvisor acts as a wrapper around the specified node process - it has to do this in order to be able to pause and restart this process. As such, you need to run your node _via_ Nymvisor!
|
||||
|
||||
The interface to the `nymvisor run <ARGS>` command is quite simple. Any argument passed after the `run` command will be passed directly to the underlying daemon, for example: `nymvisor run run --id my-mixnode` will run the `$DAEMON_NAME run --id my-mixnode` command (where `DAEMON_NAME` is the name of the binary itself (e.g. `nym-api`, `nym-mixnode`, etc.)).
|
||||
|
||||
`run` Nymvisor and start your node via the following command. Make sure to stop any existing node before running this command.
|
||||
|
||||
```
|
||||
./nymvisor run run --id <NODE_ID>
|
||||
```
|
||||
|
||||
~~~admonish example collapsible=true title="Console output"
|
||||
```
|
||||
<!-- cmdrun ../../../../target/release/nymvisor run run --id my-node -->
|
||||
```
|
||||
~~~
|
||||
|
||||
Nymvisor will now manage your node process (for an in-depth overview of this command check the [in-depth command information](./nymvisor-upgrade.md#commands-in-depth) below). It will periodically poll [this endpoint](https://nymtech.net/.wellknown/nym-mixnode/upgrade-info.json) (replace `nym-mixnode` with whatever node you may actually be running via Nymvisor) and check for a new `version` of the binary it is watching. If this exists, it will then, using the information there:
|
||||
* pause your node process
|
||||
* grab the new binary (`version`)
|
||||
* verify it against the provided `checksum`
|
||||
* perform a data backup of the existing node
|
||||
* replace the old binary with the new one
|
||||
* restart the process
|
||||
|
||||
And that's it! Check the [maintenance page](./maintenance.md#for-nymvisor) for information on Nymvisor process maintenance and automation, and you can find more in-depth information about the various aspects of Nymvisor such as what happens [under the hood](#commands-in-depth) for various commands.
|
||||
|
||||
### Creating an Adhoc Upgrade
|
||||
`nymvisor add-upgrade <PATH_TO_EXECUTABLE> --upgrade-name=<NAME> --arg1=value1 --arg2=value2 ...` can be used to amend an existing `upgrade-plan.json` by creating new entries or to add an executable to an existing scheduled upgrade so that it would not have to be downloaded.
|
||||
|
||||
>Generally users **will not have to use this command**. Situations in which this command might be used are:
|
||||
> - an adhoc upgrade if e.g. a patched version of a binary was required
|
||||
> - if a user doesn't trust the verification process of Nymvisor's pipeline and wishes to build/verify the binary themselves before using Nymvisor to perform the upgrade
|
||||
> - if a user isn't using a currently supported operating system and needs to manually specify a binary they have built themselves
|
||||
|
||||
Similarly to `init`, `add-upgrade` requires a positional argument specifying a valid path to the upgrade binary. Furthermore, the `--upgrade-name` keyword argument must be set in order to declare the upgrade name. The remaining arguments are optional. They include:
|
||||
- `--force` - if specified, will allow Nymvisor to overwrite existing upgrade binary / `upgrade-info.json` files if they already exist
|
||||
- `--add-binary` - indicate that this command should only add binary to an existing scheduled upgrade
|
||||
- `--now` - if specified will force the upgrade to be performed immediately (technically not 'immediately' within few seconds). It can't be specified alongside either `--upgrade-time` or `--upgrade-delay` arguments
|
||||
- `--publish-date` - if a new `upgrade-info.json` file is going to be created, this argument will specify the `publish_date` metadata field. Otherwise, the current time will be used. The [RFC3339 datetime](https://www.rfc-editor.org/rfc/rfc3339) format is expected
|
||||
- `--upgrade-time` - specifies the time at which the provided upgrade will be performed (RFC3339 formatted). If left unset, the upgrade will be performed in 15 minutes. It can't be specified alongside either `--now` or `--upgrade-delay` arguments.
|
||||
- `--upgrade-delay` - specifies delay until the provided upgrade is going to get performed. If let unset, the upgrade will be performed in 15 minutes. It can't be specified alongside either `--upgrade_time` or `--now` arguments.
|
||||
|
||||
## Config
|
||||
The output format of `nymvisor config` can be further configured with `--output` argument. By default a human-readable text representation is used:
|
||||
```
|
||||
id: nym-mixnode-default
|
||||
daemon name: nym-mixnode
|
||||
daemon home: /home/nym/.nym/mixnodes/my-mixnode
|
||||
upstream base upgrade url: https://nymtech.net/.wellknown/
|
||||
disable nymvisor logs: false
|
||||
CUSTOM upgrade data directory ""
|
||||
upstream absolute upgrade url: ""
|
||||
allow binaries download: true
|
||||
enforce download checksum: true
|
||||
restart after upgrade: true
|
||||
restart on failure: false
|
||||
on failure restart delay: 10s
|
||||
max startup failures: 10
|
||||
startup period duration: 2m
|
||||
shutdown grace period: 10s
|
||||
CUSTOM backup data directory ""
|
||||
UNSAFE skip backups false
|
||||
```
|
||||
|
||||
Adding `--output=json` would format the same data into JSON which can be more easily parsed programmatically to e.g. pipe the output into `jq` for further processing.
|
||||
```
|
||||
nymvisor config --output=json
|
||||
```
|
||||
outputs:
|
||||
```
|
||||
{"nymvisor":{"id":"nym-mixnode-default","upstream_base_upgrade_url":"https://nymtech.net/.wellknown/","upstream_polling_rate":"1h","disable_logs":false,"upgrade_data_directory":null},"daemon":{"name":"nym-mixnode","home":"/home/nym/.nym/mixnodes/my-mixnode","absolute_upstream_upgrade_url":null,"allow_binaries_download":true,"enforce_download_checksum":true,"restart_after_upgrade":true,"restart_on_failure":false,"failure_restart_delay":"10s","max_startup_failures":10,"startup_period_duration":"2m","shutdown_grace_period":"10s","backup_data_directory":null,"unsafe_skip_backup":false}}
|
||||
```
|
||||
|
||||
## CLI Overview
|
||||
Command options are:
|
||||
- `help`, `--help`, or `-h` - Output Nymvisor help information and display the available commands.
|
||||
- `config` - Display the current Nymvisor configuration, that means displaying the current configuration file that might have been overridden with environment variables value that Nymvisor is using.
|
||||
- `init` - Generate a `config.toml` file for this instance of Nymvisor that will use the provided arguments alongside any environmental variables that are set.
|
||||
- `add-upgrade` - Add an upgrade manually to Nymvisor. This command allows you to easily add the binary corresponding to an upgrade or amend the existing `upgrade-plan.json` whilst creating new `upgrade-info.json` file.
|
||||
- `build-info` - Output the build information.
|
||||
- `daemon-build-info` - Output the build information of the current binary used by the associated daemon.
|
||||
- `run` - Run the configured binary using the rest of the provided arguments.
|
||||
- `-V` or `--version` - Output the Nymvisor version
|
||||
|
||||
Similarly to other Nym binaries, Nymvisor supports a global `--config-env-file` or `-c` flag that allows specifying path to a `.env` file defining any relevant environmental variables that are going to be applied to any of the Nymvisor commands as described in the [Environment section](./nymvisor-upgrade.md#environment-variables).
|
||||
|
||||
For commands that depend on Nymvisor config file (i.e. all but `init`), the configuration file is loaded as follows:
|
||||
- if available, reading `$NYMVISOR_CONFIG_PATH`
|
||||
- otherwise, if `$NYMVISOR_ID` is set, a default path will be used, i.e. `$HOME/.nym/nymvisors/instances/$NYMVISOR_ID/config/config.toml`
|
||||
- finally, if there's only a single `nymvisor` instance instantiated (as defined by directories in `$HOME/.nym/nymvisors/instances`), that one will be loaded
|
||||
- if all of the above fails, an error is returned
|
||||
|
||||
Nymvisor attempts to load the file from the derived path. If it fails, it attempts to use one of the older schemas to and upgrade it as it goes, the loaded configuration is then overridden with any value that might have been set in the environment.
|
||||
|
||||
## Environment Variables
|
||||
|
||||
> Please note environmental variables take precedence over any arguments passed, i.e. if one were to specify `--daemon_home="/foo"` and set `DAEMON_HOME="bar"`, the value of `"bar"` would end up being used.
|
||||
|
||||
For any of its commands as described in [CLI Overview section](./nymvisor-upgrade.md#cli-overview), Nymvisor reads its configuration from the following environment variables:
|
||||
|
||||
- `NYMVISOR_ID` is the human-readable identifier of the particular Nymvisor instance.
|
||||
- `NYMVISOR_CONFIG_PATH` is used to manually override path to the configuration file of the Nymvisor instance.
|
||||
- `NYMVISOR_UPSTREAM_BASE_UPGRADE_URL` (defaults to https://nymtech.net/.wellknown/) is the base url of the upstream source for obtaining upgrade information for the daemon. It will be used fo constructing the full url, i.e. `$NYMVISOR_UPSTREAM_BASE_UPGRADE_URL/$DAEMON_NAME/upgrade-info.json`.
|
||||
- `NYMVISOR_UPSTREAM_POLLING_RATE` (defaults to 1h) is polling rate the upstream url for upgrade information.
|
||||
- `NYMVISOR_DISABLE_LOGS` (defaults to `false`). If set to `true`, this will disable Nymvisor logs (but not the underlying process) completely.
|
||||
- `NYMVISOR_UPGRADE_DATA_DIRECTORY` is the custom directory for upgrade data - binaries and upgrade plans. If not set, the global Nymvisors' data directory will be used instead.
|
||||
- `DAEMON_NAME` is the name of the binary itself (e.g. `nym-api`, `nym-mixnode`, etc.).
|
||||
- `DAEMON_HOME` is the location where the `nymvisor/` directory is kept that contains the auxiliary files associated with the underlying daemon instance, such as any backups or current version information, e.g. `$HOME/.nym/nym-api/my-nym-api`, `$HOME/.nym/mixnodes/my-mixnode`, etc.
|
||||
- `DAEMON_ABSOLUTE_UPSTREAM_UPGRADE_URL` is the absolute (i.e. the full url) upstream source for upgrade plans for this daemon. The url has to point to an endpoint containing a valid `UpgradeInfo` json file. If set it takes precedence over `NYMVISOR_UPSTREAM_BASE_UPGRADE_URL`.
|
||||
- `DAEMON_ALLOW_BINARIES_DOWNLOAD` (defaults to `true`), if set to `true`, it will enable auto-downloading of new binaries (as declared by urls in corresponding `upgrade-info.json` files). For security reasons one might wish to disable it and instead manually provide binaries by either placing them in the appropriate directory or by invoking `add-upgrade` command.
|
||||
- `DAEMON_ENFORCE_DOWNLOAD_CHECKSUM` (defaults to `true`), if set to `true` Nymvisor will require that a checksum is provided in the upgrade plan for the upgrade binary to be downloaded. If disabled, Nymvisor will not require a checksum to be provided, but still check the checksum if one is provided.
|
||||
- `DAEMON_RESTART_AFTER_UPGRADE` (defaults to `true`), if set to `true` Nymvisor will restart the subprocess with the same command-line arguments and flags (but with the new binary) after a successful upgrade. Otherwise (`false`), Nymvisor stops running after an upgrade and requires the system administrator to manually restart it. **Note restart is only after the upgrade and does not auto-restart the subprocess after an error occurs.** That is controlled via `DAEMON_RESTART_ON_FAILURE`.
|
||||
- `DAEMON_RESTART_ON_FAILURE` (defaults to `true`), if set to `true`, Nymvisor will restart the subprocess with the same command-line arguments and flags if it has terminated with a non-zero exit code.
|
||||
- `DAEMON_FAILURE_RESTART_DELAY` (defaults to 10s), if `DAEMON_RESTART_ON_FAILURE` is set to `true`, this will specify a delay between the process shutdown (with a non-zero exit code) and it being restarted.
|
||||
- `DAEMON_MAX_STARTUP_FAILURES` (defaults to 10) if `DAEMON_RESTART_ON_FAILURE` is set to `true`, this defines the maximum number of startup failures the subprocess can experience in a quick succession before no further restarts will be attempted and Nymvisor will terminate.
|
||||
- `DAEMON_STARTUP_PERIOD_DURATION` (defaults to 120s) if `DAEMON_RESTART_ON_FAILURE` is set to `true`, this defines the length of time during which the subprocess is still considered to be in the startup phase when its failures are going to be counted towards the limit defined in `DAEMON_MAX_STARTUP_FAILURES`.
|
||||
- `DAEMON_SHUTDOWN_GRACE_PERIOD` (defaults to 10s), specifies the amount of time Nymvisor is willing to wait for the subprocess to undergo graceful shutdown after receiving an interrupt before it sends a kill signal.
|
||||
- `DAEMON_BACKUP_DATA_DIRECTORY` specifies custom backup directory for daemon data. If not set, `DAEMON_HOME/nymvisor/backups` is used instead.
|
||||
- `DAEMON_UNSAFE_SKIP_BACKUP` (defaults to `false`), if set to `true`, all upgrades will be performed directly without performing any backups. Otherwise (`false`), Nymvisor will back up the contents of `DAEMON_HOME` before trying the upgrade.
|
||||
|
||||
## Dir structure
|
||||
The folder structure of Nymvisor is heavily inspired by Cosmovisor, but with some notable changes to accommodate our binaries having possibly multiple instances due to their different `--id` flags. The data is spread through three main directories:
|
||||
- in a global `nymvisors` data directory shared by all Nymvisor instances (default: `$HOME/.nym/nymvisors/data`) that contains daemon upgrade plans, binaries and upgrades histories. It includes a subdirectory for each version of the application (i.e. `genesis` or `upgrades<name>`). Within each subdirectory is the application binary (i.e. `bin/$DAEMON_NAME`), the associated `upgrade-info.json` and any additional auxiliary files associated with each binary. `current` is a symbolic link to the currently active directory (i.e. `genesis` or `upgrades/<NAME>`)
|
||||
- in a home directory of a particular `nymvisor` instance (e.g. `$HOME/.nym/nymvisors/instances/<nymvisor-instance-id>/`). It includes subdirectories for its configuration file (i.e. `config/config.toml`), that preconfigures the instance, and for any additional persistent data that might be added in the future (i.e. `data`)
|
||||
- in a `nymvisor` data directory inside the home directory of the managed daemon instance (default: `$HOME/.nym/$DAEMON_NAME/nymvisor`) that contains subdirectories for data backups (i.e. `backups/<name>`) and current version information (`current-version-info.json`)
|
||||
|
||||
A sample full structure looks as follows:
|
||||
|
||||
```
|
||||
~/.nym
|
||||
├── nymvisors
|
||||
│ ├── instances
|
||||
│ │ ├── <id1>
|
||||
│ │ │ ├── config
|
||||
│ │ │ │ └── config.toml
|
||||
│ │ │ └── data
|
||||
│ │ │ └── ...
|
||||
│ │ └── <id2>
|
||||
│ │ └── ...
|
||||
│ └── data
|
||||
│ ├── nym-api
|
||||
│ │ ├── current -> genesis or upgrades/<name>
|
||||
│ │ ├── genesis
|
||||
│ │ │ ├── bin
|
||||
│ │ │ │ └── nym-api
|
||||
│ │ │ └── upgrade-info.json
|
||||
│ │ ├── upgrades
|
||||
│ │ │ └── <upgrade-name>
|
||||
│ │ │ ├── bin
|
||||
│ │ │ │ └── nym-api
|
||||
│ │ │ └── upgrade-info.json
|
||||
│ │ ├── upgrade-history.json
|
||||
│ │ └── upgrade-plan.json
|
||||
│ ├── nym-mixnode
|
||||
│ │ └── ...
|
||||
│ └── $DAEMON_NAME
|
||||
│ └── ...
|
||||
└── nym-api
|
||||
├── <id1>
|
||||
│ ├── config
|
||||
│ │ └── <nym-api-config-data>
|
||||
│ ├── data
|
||||
│ │ └── <nym-api-data>
|
||||
│ └── nymvisor
|
||||
│ ├── backups
|
||||
│ │ └── <upgrade-name>
|
||||
│ │ └── ....
|
||||
│ └── current-version-info.json
|
||||
└── <id2>
|
||||
└── ...
|
||||
```
|
||||
|
||||
## Commands In-Depth
|
||||
This section outlines what happens under the hood with the following commands:
|
||||
|
||||
### Init
|
||||
`init` does the following:
|
||||
- executes the `$DAEMON_NAME build-info` command on the daemon executable to check its validity and obtain its name
|
||||
- creates the required directory structure:
|
||||
- `$DAEMON_HOME/nymvisor` folder if it doesn't yet exist
|
||||
- `$DAEMON_BACKUP_DATA_DIRECTORY` folder if it doesn't yet exist
|
||||
- `$NYMVISOR_UPGRADE_DATA_DIRECTORY` folder if it doesn't yet exist
|
||||
- `$NYMVISOR_UPGRADE_DATA_DIRECTORY/$DAEMON_NAME/genesis/bin` folder if it doesn't yet exist
|
||||
- `$NYMVISOR_UPGRADE_DATA_DIRECTORY/$DAEMON_NAME/upgrades` folder if it doesn't yet exist
|
||||
- copies the provided executable to `$NYMVISOR_UPGRADE_DATA_DIRECTORY/$DAEMON_NAME/genesis/bin/$DAEMON_NAME`
|
||||
- generates initial `$NYMVISOR_UPGRADE_DATA_DIRECTORY/$DAEMON_NAME/genesis/upgrade-info.json` file based on the provided binary
|
||||
- generates initial `$DAEMON_HOME/nymvisor/current-version-info.json` file based on the provided binary
|
||||
- creates a `$NYMVISOR_UPGRADE_DATA_DIRECTORY/$DAEMON_NAME/current` symlink pointing to `$NYMVISOR_UPGRADE_DATA_DIRECTORY/$DAEMON_NAME/genesis`
|
||||
- saves the Nymvisor instance's config file to `$NYMVISOR_CONFIG_PATH` and creates the full directory structure for the file
|
||||
- outputs (to `stdout`) the full configuration used
|
||||
|
||||
> `nymvisor init` is specifically for initializing Nymvisor, and should **not** be confused with a daemon's `init` command - such as `nym-mixnode init` (e.g. `cosmovisor run init`).
|
||||
|
||||
### Run
|
||||
`nymvisor run` is a lightweight wrapper around the underlying daemon. It uses only a single thread and spawns three simple tasks:
|
||||
- an upstream poller that checks the upstream source (as defined by `DAEMON_ABSOLUTE_UPSTREAM_UPGRADE_URL` or derived from `NYMVISOR_UPSTREAM_BASE_UPGRADE_URL`) for any recently released upgrades. It then creates appropriate `upgrade-info.json` file and updates the `upgrade-plan.json`
|
||||
- a file watcher for the `upgrade-plan.json` file that can notify the main run loop of upgrades that were added by either the above upstream poller task or via the `add-upgrade` command,
|
||||
- the daemon run loop that:
|
||||
- runs the `DAEMON_NAME` with the provided arguments until:
|
||||
- it completes the execution (with any exit code),
|
||||
- Nymvisor receives a `SIGINT`, `SIGTERM` or `SIGQUIT`,
|
||||
- a new upgrade is scheduled to be performed (by other task watching for changes in `upgrade-plan.json` and waiting until the `upgrade_time`,
|
||||
- if `DAEMON_UNSAFE_SKIP_BACKUP` is not set to `true`, it backups the content of `DAEMON_HOME` directory,
|
||||
- performs the binary upgrade by:
|
||||
- creating a temporary, exclusive and non-blocking, `upgrade.lock` file for the `DAEMON_NAME`. `flock` with `LOCK_EX | LOCK_NB` is used for that purpose. The file is created in case users didn't read any warnings and attempted to run multiple instances of `nymvisor` managing the same `DAEMON_NAME`,
|
||||
- downloading the upgrade binary for the runners architecture using one of the urls defined in `upgrade-info.json`. Note, however, that this is only done if the binary associated with the `<UPGRADE-NAME>` does not already exist and `DAEMON_ALLOW_DOWNLOAD_BINARIES` is set to `true`,
|
||||
- if the binary has been downloaded and `DAEMON_ENFORCE_DOWNLOAD_CHECKSUM` is set to true, the file checksum is verified using the specified algorithm,
|
||||
- verifying the upgrade binary - checking if it's a valid executable with expected `build-info`. Note that this will also set `a+x` bits on the file if those permissions have not already been set,
|
||||
- removing the queued upgrade from `upgrade-plan.json`,
|
||||
- inserting new upgrade into the `upgrade-history.json`,
|
||||
- updating the `current-version-info.json`,
|
||||
- updating the `$NYMVISOR_UPGRADE_DATA_DIRECTORY/$DAEMON_NAME/current` symlink to the upgrade directory,
|
||||
- removing the `upgrade.lock` file.
|
||||
- the above loop is repeated if either:
|
||||
- the daemon has crashed and `DAEMON_MAX_STARTUP_FAILURES` has not been reached yet,
|
||||
- the daemon has successfully been upgraded, `DAEMON_RESTART_AFTER_UPGRADE` has been set to `true` and the manual flag on the performed upgrade has been set to `false`.
|
||||
|
||||
### Add-Upgrade
|
||||
`nymvisor add-upgrade` does the following:
|
||||
- executes the `$DAEMON_NAME build-info` command on the daemon executable to check its validity and obtain its name
|
||||
- attempts to load existing `upgrade-info.json` for the provided `<upgrade-name>`. If it already exists and neither `--force` nor `--add-binary` was specified, Nymvisor will terminate
|
||||
- checks if `upgrades/<upgrade-name>/$DAEMON_NAME` binary already exists. If it does and `--force` flag was not specified, Nymvisor will terminate the provided upgrade binary is copied to its appropriate location
|
||||
- if applicable, new `upgrade-info.json` is created and written to its appropriate location
|
||||
- `upgrade-plan.json` is updated with the new upgrade details. If there's an active Nymvisor instance running, this change will be detected to initialise upgrade process
|
||||
@@ -216,7 +216,7 @@ You can use the following command to download them for the correct network:
|
||||
wget -O $HOME/.nyxd/config/genesis.json https://nymtech.net/genesis/genesis.json
|
||||
|
||||
# Sandbox testnet
|
||||
curl https://rpc.sandbox.nymtech.net/snapshots/genesis.json | jq '.result.genesis' > $HOME/.nyxd/config/genesis.json
|
||||
wget -O $HOME/.nyxd/config/genesis.json https://sandbox-validator1.nymtech.net/snapshots/genesis.json | jq '.result.genesis'
|
||||
```
|
||||
|
||||
### `config.toml` configuration
|
||||
@@ -232,7 +232,7 @@ laddr = "tcp://0.0.0.0:26656"
|
||||
```
|
||||
# Sandbox testnet
|
||||
cors_allowed_origins = ["*"]
|
||||
persistent_peers = "26f7782aff699457c8e6dd9a845e5054c9b0707e@:3.72.19.120:26656"
|
||||
persistent_peers = "26f7782aff699457c8e6dd9a845e5054c9b0707e@sandbox-validator1.nymtech.net:26666"
|
||||
laddr = "tcp://0.0.0.0:26656"
|
||||
```
|
||||
|
||||
@@ -254,7 +254,7 @@ And if you wish to add a human-readable moniker to your node:
|
||||
Finally, if you plan on using [Cockpit](https://cockpit-project.org/documentation.html) on your server, change the `grpc` port from `9090` as this is the port used by Cockpit.
|
||||
|
||||
### `app.toml` configuration
|
||||
In the file `$HOME/.nyxd/config/app.toml`, set the following values:
|
||||
In the file `$HOME/nyxd/config/app.toml`, set the following values:
|
||||
|
||||
```
|
||||
# Mainnet
|
||||
@@ -264,6 +264,7 @@ minimum-gas-prices = "0.025unym,0.025unyx"
|
||||
```
|
||||
# Sandbox Testnet
|
||||
minimum-gas-prices = "0.025unym,0.025unyx"
|
||||
enable = true` in the `[api]` section to get the API server running
|
||||
```
|
||||
|
||||
### Setting up your validator's admin user
|
||||
@@ -303,31 +304,6 @@ File at /path/to/genesis.json is a valid genesis file
|
||||
|
||||
> If this test did not pass, check that you have replaced the contents of `/<PATH-TO>/.nyxd/config/genesis.json` with that of the correct genesis file.
|
||||
|
||||
### Setting up nyxd as full node (non-signing)
|
||||
|
||||
```admonish danger title=""
|
||||
Skip this section if you're planning to run a validator node to join network consensus. To ensure security & maximum availability of validators, do not expose additional services to the Internet
|
||||
```
|
||||
|
||||
Unlike signing validators, full nodes do not propose / sign blocks. A full node is typically used for indexing blocks produced on the chain and for exposing web interfaces such as RPC, API and gRPC endpoints required for external applications/services to interact with the blockchain.
|
||||
|
||||
By default, API server is disabled and RPC/gRPC servers listen to the loopback address only. In a production setup, it is recommended to use a webserver such as Nginx or caddy to proxy requests to the endpoints as required.
|
||||
|
||||
To enable Cosmos REST API, you can enable it in `$HOME/.nyxd/config/app.toml` like :
|
||||
|
||||
```
|
||||
[api]
|
||||
|
||||
# Enable defines if the API server should be enabled. Toggle this to `true`
|
||||
enable = true
|
||||
|
||||
# Swagger defines if swagger documentation should automatically be registered.
|
||||
# You can also expose swagger documentation by toggling the below configuration to true
|
||||
swagger = true
|
||||
```
|
||||
|
||||
For more information on enabling access to various endpoints via Nginx, refer to the [example configuration here](./maintenance.md#setup)
|
||||
|
||||
### Open firewall ports
|
||||
|
||||
Before starting the validator, we will need to open the firewall ports:
|
||||
@@ -343,9 +319,6 @@ sudo ufw enable
|
||||
# 22 : Default SSH port
|
||||
sudo ufw allow 26656,26660,22
|
||||
|
||||
## !! FOR FULL NODES ONLY !! - exposing Nginx for serving web requests
|
||||
sudo ufw allow 80,443
|
||||
|
||||
# to check everything worked
|
||||
sudo ufw status
|
||||
```
|
||||
@@ -373,7 +346,7 @@ sudo apt install snapd -y
|
||||
sudo snap install lz4
|
||||
|
||||
# download the snapshot
|
||||
wget -O nyxd-sandbox-snapshot-data.tar.lz4 https://rpc.sandbox.nymtech.net/snapshots/nyxd-sandbox-snapshot-data.tar.lz4
|
||||
wget -O nyxd-sandbox-snapshot-data.tar.lz4 https://sandbox-validator1.nymtech.net/snapshots/nyxd-sandbox-snapshot-data.tar.lz4
|
||||
|
||||
# reset your validator state
|
||||
nyxd tendermint unsafe-reset-all
|
||||
@@ -385,8 +358,10 @@ lz4 -c -d nyxd-sandbox-snapshot-data.tar.lz4 | tar -x -C $HOME/.nyxd
|
||||
You can then restart `nyxd` - it should start syncing from a block > 2000000.
|
||||
|
||||
### Joining Consensus
|
||||
```admonish info title=""
|
||||
You can skip this section if you are planning to run a full-node. This step will make your node a signing validator which joins network consensus
|
||||
```admonish caution title=""
|
||||
When joining consensus, make sure that you do not disrupt (or worse - halt) the network by coming in with a disproportionately large amount of staked tokens.
|
||||
|
||||
Please initially stake a small amount of tokens compared to existing validators, then delegate to yourself in tranches over time.
|
||||
```
|
||||
|
||||
Once your validator has synced and you have received tokens, you can join consensus and produce blocks.
|
||||
@@ -423,7 +398,7 @@ nyxd tx staking create-validator
|
||||
--gas-adjustment=1.15
|
||||
--gas-prices=0.025unyx
|
||||
--from=<"KEYRING_NAME">
|
||||
--node https://rpc.sandbox.nymtech.net:443
|
||||
--node https://sandbox-validator1.nymtech.net:443
|
||||
```
|
||||
|
||||
You'll need Nyx tokens on mainnet / sandbox to perform the above tasks.
|
||||
@@ -463,6 +438,7 @@ With above command you can specify the `gpg` key last numbers (as used in `keyba
|
||||
### Automating your validator with systemd
|
||||
You will most likely want to automate your validator restarting if your server reboots. Checkout the [maintenance page](./maintenance.md#systemd) with a quick tutorial.
|
||||
|
||||
|
||||
### Setting the ulimit
|
||||
|
||||
Linux machines limit how many open files a user is allowed to have. This is called a `ulimit`. We need to set it to a higher value than the default 1024. Follow the instructions in the [maintenance page](./maintenance.md#Setting-the-ulimit) to change the `ulimit` value for validators.
|
||||
@@ -498,15 +474,11 @@ To upgrade your validator, follow the steps on the [maintenance page](./maintena
|
||||
|
||||
#### Common reasons for your validator being jailed
|
||||
|
||||
Your validator will be jailed if your node:
|
||||
- misses _`x`_ amount of blocks in _`y`_ interval, where _`x`_ and _`y`_ are parameters set by chain governance
|
||||
- performs double signing (two conflicting signatures on the same block using the same key)
|
||||
The most common reason for your validator being jailed is that your validator is out of memory because of bloated syslogs.
|
||||
|
||||
Double signing is a serious infraction. If a node double signs, all the delegators to the node (including self-delegation) will be slashed by 5%. Additionally, the node will be permanently jailed and removed from consensus (called _tombstoning_)
|
||||
Running the command `df -H` will return the size of the various partitions of your VPS.
|
||||
|
||||
One of the most common reason for your validator being jailed is that your validator is out of memory because of bloated syslogs.
|
||||
|
||||
Running the command `df -H` will return the size of the various partitions of your VPS. If the partition with blockchain data is almost full, try pruning the blockchain data or expanding the storage size.
|
||||
If the `/dev/sda` partition is almost full, try pruning some of the `.gz` syslog archives and restart your validator process.
|
||||
|
||||
### Day 2 operations with your validator
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user