Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a31f7de7c9 | |||
| e7c8de8eec | |||
| e27a2ae857 | |||
| 0de0ad91bd | |||
| db2769b59b | |||
| d1c12c0b22 | |||
| 2e0c0bfdc5 | |||
| ccf97e8570 | |||
| 56a8b82c4d | |||
| 876beed97d | |||
| de450f87de | |||
| 2d55d09f24 | |||
| aa8926ed5d | |||
| 5df820db6c | |||
| 20c144c236 |
Generated
+111
-9
@@ -76,8 +76,13 @@ checksum = "94a45b455c14666b85fc40a019e8ab9eb75e3a124e05494f5397122bc9eb06e0"
|
|||||||
name = "app"
|
name = "app"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bandwidth-claim-contract",
|
||||||
|
"bip39",
|
||||||
"coconut-interface",
|
"coconut-interface",
|
||||||
|
"cosmwasm-std",
|
||||||
"credentials",
|
"credentials",
|
||||||
|
"cw3-flex-multisig",
|
||||||
|
"network-defaults",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tauri",
|
"tauri",
|
||||||
@@ -1002,9 +1007,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cosmwasm-crypto"
|
name = "cosmwasm-crypto"
|
||||||
version = "1.0.0-beta4"
|
version = "1.0.0-beta5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f903ebbabc0d4880dbc76148efb8be8fc29fa4bf294c440c3d70da1c8bcafff7"
|
checksum = "8904127a5b9e325ef5d6b2b3f997dcd74943cd35097139b1a4d15b1b6bccae66"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"digest 0.9.0",
|
"digest 0.9.0",
|
||||||
"ed25519-zebra",
|
"ed25519-zebra",
|
||||||
@@ -1015,18 +1020,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cosmwasm-derive"
|
name = "cosmwasm-derive"
|
||||||
version = "1.0.0-beta4"
|
version = "1.0.0-beta5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "832bebef577ecb394603de8e2bf0de429b74aa364e17dec18e15ce37e71b0cae"
|
checksum = "a14364ac4d9d085867929d0cf3e94b1d2100121ce02c33c72961406830002613"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cosmwasm-std"
|
name = "cosmwasm-std"
|
||||||
version = "1.0.0-beta4"
|
version = "1.0.0-beta5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6238c45840cc9de5a39f0f619e3a4f7c38c5d2c6ac9e3e4d72751ee045e6d7da"
|
checksum = "e2ece12e5bbde434b93937d7b2107e6291f11d69ffa72398c50e8bab41d451d3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"cosmwasm-crypto",
|
"cosmwasm-crypto",
|
||||||
@@ -1336,6 +1341,99 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cw-storage-plus"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c087ff98fb0475db4c2b5298a5fd12b2848d2854b39d1115d930ee6da24d1eed"
|
||||||
|
dependencies = [
|
||||||
|
"cosmwasm-std",
|
||||||
|
"schemars",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cw-utils"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e3396c7aff5a0e3fb6dcc6cc89f56862c1d212b40d93ed725a6962955b1887ff"
|
||||||
|
dependencies = [
|
||||||
|
"cosmwasm-std",
|
||||||
|
"schemars",
|
||||||
|
"serde",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cw2"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4f8a6500c396e33f6a7b05d35a5124eb3e394cdb6ca901f7e88332870407896c"
|
||||||
|
dependencies = [
|
||||||
|
"cosmwasm-std",
|
||||||
|
"cw-storage-plus 0.12.1",
|
||||||
|
"schemars",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cw3"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "017b6263414c58081cea97626f4d8da2dc8f7267337bba0eb5770260d26251e0"
|
||||||
|
dependencies = [
|
||||||
|
"cosmwasm-std",
|
||||||
|
"cw-utils",
|
||||||
|
"schemars",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cw3-fixed-multisig"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "949d65e60dbe8a24fc58b6b33143328af0abcc72e108a7ff80d2f3f8cabdf63b"
|
||||||
|
dependencies = [
|
||||||
|
"cosmwasm-std",
|
||||||
|
"cw-storage-plus 0.12.1",
|
||||||
|
"cw-utils",
|
||||||
|
"cw2",
|
||||||
|
"cw3",
|
||||||
|
"schemars",
|
||||||
|
"serde",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cw3-flex-multisig"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "297fe0521cf453ed58b582262cdb045862f126eb9390432e5689774badcfa370"
|
||||||
|
dependencies = [
|
||||||
|
"cosmwasm-std",
|
||||||
|
"cw-storage-plus 0.12.1",
|
||||||
|
"cw-utils",
|
||||||
|
"cw2",
|
||||||
|
"cw3",
|
||||||
|
"cw3-fixed-multisig",
|
||||||
|
"cw4",
|
||||||
|
"schemars",
|
||||||
|
"serde",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cw4"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f22da7845e99e5a277523d61c19bda3171ec3dd1084b9ca6ebac6b2fd0cdf084"
|
||||||
|
dependencies = [
|
||||||
|
"cosmwasm-std",
|
||||||
|
"cw-storage-plus 0.12.1",
|
||||||
|
"schemars",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "darling"
|
name = "darling"
|
||||||
version = "0.10.2"
|
version = "0.10.2"
|
||||||
@@ -3987,6 +4085,8 @@ version = "0.12.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"attohttpc 0.18.0",
|
"attohttpc 0.18.0",
|
||||||
|
"bandwidth-claim-contract",
|
||||||
|
"bip39",
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"clap 2.33.3",
|
"clap 2.33.3",
|
||||||
"coconut-interface",
|
"coconut-interface",
|
||||||
@@ -3994,6 +4094,8 @@ dependencies = [
|
|||||||
"console-subscriber",
|
"console-subscriber",
|
||||||
"credentials",
|
"credentials",
|
||||||
"crypto",
|
"crypto",
|
||||||
|
"cw3",
|
||||||
|
"cw3-flex-multisig",
|
||||||
"dirs",
|
"dirs",
|
||||||
"dotenv",
|
"dotenv",
|
||||||
"futures",
|
"futures",
|
||||||
@@ -7726,7 +7828,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"config",
|
"config",
|
||||||
"cosmwasm-std",
|
"cosmwasm-std",
|
||||||
"cw-storage-plus",
|
"cw-storage-plus 0.11.1",
|
||||||
"mixnet-contract-common",
|
"mixnet-contract-common",
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -7740,7 +7842,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"config",
|
"config",
|
||||||
"cosmwasm-std",
|
"cosmwasm-std",
|
||||||
"cw-storage-plus",
|
"cw-storage-plus 0.11.1",
|
||||||
"mixnet-contract-common",
|
"mixnet-contract-common",
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -8247,4 +8349,4 @@ checksum = "615120c7a2431d16cf1cf979e7fc31ba7a5b5e5707b29c8a99e5dbf8a8392a33"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ build = "src/build.rs"
|
|||||||
tauri-build = { version = "1.0.0-beta.2" }
|
tauri-build = { version = "1.0.0-beta.2" }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
cw3-flex-multisig = "0.12.1"
|
||||||
|
cosmwasm-std = "1.0.0-beta5"
|
||||||
|
bip39 = "1.0.1"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
tauri = { version = "1.0.0-beta.4", features = [] }
|
tauri = { version = "1.0.0-beta.4", features = [] }
|
||||||
@@ -23,7 +26,9 @@ url = "2.2"
|
|||||||
|
|
||||||
coconut-interface = { path = "../../../common/coconut-interface" }
|
coconut-interface = { path = "../../../common/coconut-interface" }
|
||||||
credentials = { path = "../../../common/credentials" }
|
credentials = { path = "../../../common/credentials" }
|
||||||
validator-client = {path = "../../../common/client-libs/validator-client"}
|
validator-client = {path = "../../../common/client-libs/validator-client", features = ["nymd-client"] }
|
||||||
|
bandwidth-claim-contract = { path = "../../../common/bandwidth-claim-contract" }
|
||||||
|
network-defaults = { path = "../../../common/network-defaults" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["custom-protocol"]
|
default = ["custom-protocol"]
|
||||||
|
|||||||
@@ -3,18 +3,28 @@
|
|||||||
windows_subsystem = "windows"
|
windows_subsystem = "windows"
|
||||||
)]
|
)]
|
||||||
|
|
||||||
|
use bip39::Mnemonic;
|
||||||
|
use cosmwasm_std::{to_binary, CosmosMsg, WasmMsg};
|
||||||
|
use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use bandwidth_claim_contract::msg::ExecuteMsg;
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use coconut_interface::{
|
use coconut_interface::{
|
||||||
self, hash_to_scalar, Attribute, Credential, Parameters, Signature, Theta, VerificationKey,
|
self, hash_to_scalar, Attribute, Base58, Bytable, Credential, Parameters, Signature, Theta,
|
||||||
|
VerificationKey,
|
||||||
};
|
};
|
||||||
use credentials::{obtain_aggregate_signature, obtain_aggregate_verification_key};
|
use credentials::coconut::bandwidth::{
|
||||||
|
obtain_signature, verify_credential_remote, BandwidthVoucherAttributes,
|
||||||
|
};
|
||||||
|
use credentials::obtain_aggregate_verification_key;
|
||||||
|
use validator_client::nymd::{AccountId, CosmosCoin, Decimal, Denom, NymdClient};
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
signatures: Vec<Signature>,
|
signatures: Vec<Signature>,
|
||||||
|
last_tx_hash: String,
|
||||||
n_attributes: u32,
|
n_attributes: u32,
|
||||||
params: Parameters,
|
params: Parameters,
|
||||||
serial_number: Attribute,
|
serial_number: Attribute,
|
||||||
@@ -25,19 +35,12 @@ struct State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
fn init(public_attributes_bytes: Vec<Vec<u8>>, private_attributes_bytes: Vec<Vec<u8>>) -> State {
|
fn init(public_attributes: Vec<Attribute>, private_attributes: Vec<Attribute>) -> State {
|
||||||
let n_attributes = (public_attributes_bytes.len() + private_attributes_bytes.len()) as u32;
|
let n_attributes = (public_attributes.len() + private_attributes.len()) as u32;
|
||||||
let params = Parameters::new(n_attributes).unwrap();
|
let params = Parameters::new(n_attributes).unwrap();
|
||||||
let public_attributes = public_attributes_bytes
|
|
||||||
.iter()
|
|
||||||
.map(hash_to_scalar)
|
|
||||||
.collect::<Vec<Attribute>>();
|
|
||||||
let private_attributes = private_attributes_bytes
|
|
||||||
.iter()
|
|
||||||
.map(hash_to_scalar)
|
|
||||||
.collect::<Vec<Attribute>>();
|
|
||||||
State {
|
State {
|
||||||
signatures: Vec::new(),
|
signatures: Vec::new(),
|
||||||
|
last_tx_hash: String::new(),
|
||||||
n_attributes,
|
n_attributes,
|
||||||
params,
|
params,
|
||||||
serial_number: private_attributes[0],
|
serial_number: private_attributes[0],
|
||||||
@@ -61,15 +64,40 @@ fn parse_url_validators(raw: &[String]) -> Result<Vec<Url>, String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
async fn randomise_credential(
|
async fn deposit_funds(state: tauri::State<'_, Arc<RwLock<State>>>) -> Result<String, String> {
|
||||||
idx: usize,
|
let nymd_url = Url::from_str("http://127.0.0.1:26657").unwrap();
|
||||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
let mnemonic = Mnemonic::from_str(&"sun surge soon stomach flavor country gorilla dress oblige stamp attract hip soldier agree steel prize nuclear know enjoy arm bargain always theme matter").unwrap();
|
||||||
) -> Result<Vec<Signature>, String> {
|
let nymd_client = NymdClient::connect_with_mnemonic(
|
||||||
|
network_defaults::all::Network::SANDBOX,
|
||||||
|
nymd_url.as_ref(),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
AccountId::from_str("nymt1sthrn5ep8ls5vzz8f9gp89khhmedahhdqdmmps").ok(),
|
||||||
|
mnemonic,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.expect("Could not create nymd client");
|
||||||
|
let req = ExecuteMsg::BuyBandwidth {};
|
||||||
|
let funds = vec![CosmosCoin {
|
||||||
|
denom: Denom::from_str(network_defaults::sandbox::DENOM).unwrap(),
|
||||||
|
amount: Decimal::from(1000000u64),
|
||||||
|
}];
|
||||||
|
let last_tx_hash = nymd_client
|
||||||
|
.execute(
|
||||||
|
nymd_client.erc20_bridge_contract_address().unwrap(),
|
||||||
|
&req,
|
||||||
|
Default::default(),
|
||||||
|
"",
|
||||||
|
funds,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.transaction_hash
|
||||||
|
.to_string();
|
||||||
|
println!("Tx hash: {}", last_tx_hash);
|
||||||
let mut state = state.write().await;
|
let mut state = state.write().await;
|
||||||
let signature = state.signatures.remove(idx);
|
state.last_tx_hash = last_tx_hash.clone();
|
||||||
let (new_signature, _) = signature.randomise(&state.params);
|
Ok(last_tx_hash)
|
||||||
state.signatures.insert(idx, new_signature);
|
|
||||||
Ok(state.signatures.clone())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
@@ -145,26 +173,100 @@ async fn verify_credential(
|
|||||||
// the API needs to be improved but at least it should compile (in theory)
|
// the API needs to be improved but at least it should compile (in theory)
|
||||||
let verification_key =
|
let verification_key =
|
||||||
get_aggregated_verification_key(validator_urls.clone(), state.clone()).await?;
|
get_aggregated_verification_key(validator_urls.clone(), state.clone()).await?;
|
||||||
|
let parsed_urls = parse_url_validators(&validator_urls)?;
|
||||||
|
println!("Verification key {:?}", verification_key.to_bs58());
|
||||||
let theta = prove_credential(idx, validator_urls, state.clone()).await?;
|
let theta = prove_credential(idx, validator_urls, state.clone()).await?;
|
||||||
|
|
||||||
let state = state.read().await;
|
let state = state.read().await;
|
||||||
|
|
||||||
let public_attributes_bytes = vec![
|
let public_attributes_bytes = vec![
|
||||||
state.voucher_value.to_bytes().to_vec(),
|
state.voucher_value.to_byte_vec(),
|
||||||
state.voucher_info.to_bytes().to_vec(),
|
state.voucher_info.to_byte_vec(),
|
||||||
];
|
];
|
||||||
|
|
||||||
let credential = Credential::new(
|
let mut credential = Credential::new(
|
||||||
state.n_attributes,
|
state.n_attributes,
|
||||||
theta,
|
theta.clone(),
|
||||||
public_attributes_bytes,
|
public_attributes_bytes,
|
||||||
state
|
state
|
||||||
.signatures
|
.signatures
|
||||||
.get(idx)
|
.get(idx)
|
||||||
.ok_or("Got invalid signature idx")?,
|
.ok_or("Got invalid signature idx")?,
|
||||||
|
0,
|
||||||
);
|
);
|
||||||
|
println!("Using verification key: {:?}", verification_key.to_bs58());
|
||||||
|
let local_check = credential.verify(&verification_key);
|
||||||
|
println!("Local check: {}", local_check);
|
||||||
|
if !local_check {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(credential.verify(&verification_key))
|
let mnemonic = Mnemonic::from_str("sun surge soon stomach flavor country gorilla dress oblige stamp attract hip soldier agree steel prize nuclear know enjoy arm bargain always theme matter").unwrap();
|
||||||
|
let nymd_url = Url::from_str("http://127.0.0.1:26657").unwrap();
|
||||||
|
let nymd_client = NymdClient::connect_with_mnemonic(
|
||||||
|
network_defaults::all::Network::SANDBOX,
|
||||||
|
nymd_url.as_ref(),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
AccountId::from_str("nymt1sthrn5ep8ls5vzz8f9gp89khhmedahhdqdmmps").ok(),
|
||||||
|
mnemonic,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.expect("Could not create nymd client");
|
||||||
|
let req = cw3_flex_multisig::msg::ExecuteMsg::Propose {
|
||||||
|
title: "Spend coconut".to_string(),
|
||||||
|
description: "Propose to spend a coconut cred".to_string(),
|
||||||
|
msgs: vec![CosmosMsg::Wasm(WasmMsg::Execute {
|
||||||
|
contract_addr: "nymt1sthrn5ep8ls5vzz8f9gp89khhmedahhdqdmmps".to_string(),
|
||||||
|
msg: to_binary(&ExecuteMsg::SpendCredential { amount: 1000000u64 }).unwrap(),
|
||||||
|
funds: vec![],
|
||||||
|
})],
|
||||||
|
latest: None,
|
||||||
|
};
|
||||||
|
let tx = nymd_client
|
||||||
|
.execute(
|
||||||
|
&AccountId::from_str("nymt1qwlgtx52gsdu7dtp0cekka5zehdl0uj3vqx3jd").unwrap(),
|
||||||
|
&req,
|
||||||
|
Default::default(),
|
||||||
|
"",
|
||||||
|
vec![],
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let event = tx.logs[0]
|
||||||
|
.events
|
||||||
|
.iter()
|
||||||
|
.find(|event| event.ty == "wasm")
|
||||||
|
.unwrap();
|
||||||
|
let proposal_id = u64::from_str(
|
||||||
|
&event
|
||||||
|
.attributes
|
||||||
|
.iter()
|
||||||
|
.find(|attr| attr.key == "proposal_id")
|
||||||
|
.unwrap()
|
||||||
|
.value,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
println!("Got proposal id {}", proposal_id);
|
||||||
|
credential.set_proposal_id(proposal_id);
|
||||||
|
let remote_check = verify_credential_remote(&parsed_urls, credential)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
println!("Remote check: {}", remote_check);
|
||||||
|
|
||||||
|
let req = cw3_flex_multisig::msg::ExecuteMsg::Execute { proposal_id };
|
||||||
|
nymd_client
|
||||||
|
.execute(
|
||||||
|
&AccountId::from_str("nymt1qwlgtx52gsdu7dtp0cekka5zehdl0uj3vqx3jd").unwrap(),
|
||||||
|
&req,
|
||||||
|
Default::default(),
|
||||||
|
"",
|
||||||
|
vec![],
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
Ok(remote_check)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
@@ -172,19 +274,25 @@ async fn get_credential(
|
|||||||
validator_urls: Vec<String>,
|
validator_urls: Vec<String>,
|
||||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||||
) -> Result<Vec<Signature>, String> {
|
) -> Result<Vec<Signature>, String> {
|
||||||
let guard = state.read().await;
|
let signature = {
|
||||||
let parsed_urls = parse_url_validators(&validator_urls)?;
|
let guard = state.read().await;
|
||||||
let public_attributes = vec![guard.voucher_value, guard.voucher_info];
|
let parsed_urls = parse_url_validators(&validator_urls)?;
|
||||||
let private_attributes = vec![guard.serial_number, guard.binding_number];
|
let bandwidth_credential_attributes = BandwidthVoucherAttributes {
|
||||||
|
serial_number: guard.serial_number,
|
||||||
|
binding_number: guard.binding_number,
|
||||||
|
voucher_value: guard.voucher_value,
|
||||||
|
voucher_info: guard.voucher_info,
|
||||||
|
};
|
||||||
|
|
||||||
let signature = obtain_aggregate_signature(
|
obtain_signature(
|
||||||
&guard.params,
|
&guard.params,
|
||||||
&public_attributes,
|
&bandwidth_credential_attributes,
|
||||||
&private_attributes,
|
&parsed_urls,
|
||||||
&parsed_urls,
|
guard.last_tx_hash.clone(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|err| format!("failed to obtain aggregate signature - {:?}", err))?;
|
.map_err(|err| format!("failed to obtain aggregate signature - {:?}", err))?
|
||||||
|
};
|
||||||
|
|
||||||
let mut state = state.write().await;
|
let mut state = state.write().await;
|
||||||
state.signatures.push(signature);
|
state.signatures.push(signature);
|
||||||
@@ -192,16 +300,21 @@ async fn get_credential(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let public_attributes = vec![b"public_key".to_vec()];
|
let params = coconut_interface::Parameters::new(4).unwrap();
|
||||||
let private_attributes = vec![b"private_key".to_vec()];
|
let bandwidth_credential_attributes = BandwidthVoucherAttributes {
|
||||||
|
serial_number: params.random_scalar(),
|
||||||
|
binding_number: params.random_scalar(),
|
||||||
|
voucher_value: Attribute::from(1000000u64),
|
||||||
|
voucher_info: hash_to_scalar("BandwidthVoucher"),
|
||||||
|
};
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
.manage(Arc::new(RwLock::new(State::init(
|
.manage(Arc::new(RwLock::new(State::init(
|
||||||
public_attributes,
|
bandwidth_credential_attributes.get_public_attributes(),
|
||||||
private_attributes,
|
bandwidth_credential_attributes.get_private_attributes(),
|
||||||
))))
|
))))
|
||||||
.invoke_handler(tauri::generate_handler![
|
.invoke_handler(tauri::generate_handler![
|
||||||
get_credential,
|
get_credential,
|
||||||
randomise_credential,
|
deposit_funds,
|
||||||
delete_credential,
|
delete_credential,
|
||||||
list_credentials,
|
list_credentials,
|
||||||
verify_credential
|
verify_credential
|
||||||
|
|||||||
@@ -3,9 +3,10 @@
|
|||||||
import {onMount} from "svelte";
|
import {onMount} from "svelte";
|
||||||
import QRious from "qrious";
|
import QRious from "qrious";
|
||||||
|
|
||||||
const validator_urls = ["http://localhost:8080"];
|
const validator_urls = ["http://localhost:8080", "http://localhost:8081", "http://localhost:8082"];
|
||||||
let signatures = [];
|
let signatures = [];
|
||||||
let qrVisible = false;
|
let qrVisible = false;
|
||||||
|
let tx_hash = "";
|
||||||
|
|
||||||
async function getCredential() {
|
async function getCredential() {
|
||||||
signatures = await invoke("get_credential", {
|
signatures = await invoke("get_credential", {
|
||||||
@@ -13,10 +14,8 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function randomiseCredential(idx) {
|
async function depositFunds() {
|
||||||
signatures = await invoke("randomise_credential", {
|
tx_hash = await invoke("deposit_funds");
|
||||||
idx: idx,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function verifyCredential(idx) {
|
async function verifyCredential(idx) {
|
||||||
@@ -24,7 +23,7 @@
|
|||||||
idx: idx,
|
idx: idx,
|
||||||
validatorUrls: validator_urls,
|
validatorUrls: validator_urls,
|
||||||
});
|
});
|
||||||
alert(response);
|
qrVisible = !response;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteCredential(idx) {
|
async function deleteCredential(idx) {
|
||||||
@@ -58,6 +57,7 @@
|
|||||||
<title>Coconut</title>
|
<title>Coconut</title>
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
|
<button class="btn btn-success" on:click={depositFunds}>Deposit</button>
|
||||||
<button class="btn btn-success" on:click={getCredential}>Get Credential</button>
|
<button class="btn btn-success" on:click={getCredential}>Get Credential</button>
|
||||||
<hr />
|
<hr />
|
||||||
<table class="table table-dark">
|
<table class="table table-dark">
|
||||||
@@ -67,11 +67,6 @@
|
|||||||
<td>
|
<td>
|
||||||
<div class="btn-group" role="group" aria-label="Basic example">
|
<div class="btn-group" role="group" aria-label="Basic example">
|
||||||
<button
|
<button
|
||||||
class="btn btn-primary"
|
|
||||||
on:click={() => {
|
|
||||||
randomiseCredential(idx);
|
|
||||||
}}>Randomize</button
|
|
||||||
><button
|
|
||||||
class="btn btn-danger"
|
class="btn btn-danger"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
deleteCredential(idx);
|
deleteCredential(idx);
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
// event types
|
||||||
|
pub const VOUCHER_ACQUIRED_EVENT_TYPE: &str = "coconut_acquired";
|
||||||
|
|
||||||
|
// attributes that are used in multiple places
|
||||||
|
pub const VOUCHER_VALUE: &str = "value";
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
pub mod events;
|
||||||
pub mod keys;
|
pub mod keys;
|
||||||
pub mod msg;
|
pub mod msg;
|
||||||
pub mod payment;
|
pub mod payment;
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ pub struct InstantiateMsg {}
|
|||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum ExecuteMsg {
|
pub enum ExecuteMsg {
|
||||||
LinkPayment { data: LinkPaymentData },
|
LinkPayment { data: LinkPaymentData },
|
||||||
|
BuyBandwidth {},
|
||||||
|
SpendCredential { amount: u64 },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||||
|
|||||||
@@ -189,6 +189,7 @@ impl BandwidthController {
|
|||||||
¶ms,
|
¶ms,
|
||||||
&bandwidth_credential_attributes,
|
&bandwidth_credential_attributes,
|
||||||
&self.validator_endpoints,
|
&self.validator_endpoints,
|
||||||
|
String::new(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
// the above would presumably be loaded from a file
|
// the above would presumably be loaded from a file
|
||||||
|
|||||||
@@ -2,7 +2,10 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::{validator_api, ValidatorClientError};
|
use crate::{validator_api, ValidatorClientError};
|
||||||
use coconut_interface::{BlindSignRequestBody, BlindedSignatureResponse, VerificationKeyResponse};
|
use coconut_interface::{
|
||||||
|
BlindSignRequestBody, BlindedSignatureResponse, Credential, VerificationKeyResponse,
|
||||||
|
VerifyCredentialResponse,
|
||||||
|
};
|
||||||
use mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixNodeBond};
|
use mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixNodeBond};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use validator_api_requests::models::{
|
use validator_api_requests::models::{
|
||||||
@@ -571,6 +574,13 @@ impl<C> Client<C> {
|
|||||||
) -> Result<VerificationKeyResponse, ValidatorClientError> {
|
) -> Result<VerificationKeyResponse, ValidatorClientError> {
|
||||||
Ok(self.validator_api.get_coconut_verification_key().await?)
|
Ok(self.validator_api.get_coconut_verification_key().await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn verify_credential(
|
||||||
|
&self,
|
||||||
|
request_body: &Credential,
|
||||||
|
) -> Result<VerifyCredentialResponse, ValidatorClientError> {
|
||||||
|
Ok(self.validator_api.verify_credential(request_body).await?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ApiClient {
|
pub struct ApiClient {
|
||||||
@@ -673,4 +683,11 @@ impl ApiClient {
|
|||||||
) -> Result<VerificationKeyResponse, ValidatorClientError> {
|
) -> Result<VerificationKeyResponse, ValidatorClientError> {
|
||||||
Ok(self.validator_api.get_coconut_verification_key().await?)
|
Ok(self.validator_api.get_coconut_verification_key().await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn verify_credential(
|
||||||
|
&self,
|
||||||
|
request_body: &Credential,
|
||||||
|
) -> Result<VerifyCredentialResponse, ValidatorClientError> {
|
||||||
|
Ok(self.validator_api.verify_credential(request_body).await?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ pub struct Log {
|
|||||||
// and launchpad cosmos validator was setting it to what essentially is just the raw version of what
|
// and launchpad cosmos validator was setting it to what essentially is just the raw version of what
|
||||||
// we received (and we don't care about launchpad, we, as the time of writing this, work on the stargate)
|
// we received (and we don't care about launchpad, we, as the time of writing this, work on the stargate)
|
||||||
// log: String,
|
// log: String,
|
||||||
events: Vec<cosmwasm_std::Event>,
|
pub events: Vec<cosmwasm_std::Event>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Searches in logs for the first event of the given event type and in that event
|
/// Searches in logs for the first event of the given event type and in that event
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ pub mod error;
|
|||||||
pub mod fee;
|
pub mod fee;
|
||||||
pub mod traits;
|
pub mod traits;
|
||||||
pub mod wallet;
|
pub mod wallet;
|
||||||
|
use cosmrs::rpc::endpoint::tx::Response as TxResponse;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct NymdClient<C> {
|
pub struct NymdClient<C> {
|
||||||
@@ -274,6 +275,13 @@ impl<C> NymdClient<C> {
|
|||||||
self.client.get_balance(address, denom).await
|
self.client.get_balance(address, denom).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_tx(&self, id: tx::Hash) -> Result<TxResponse, NymdError>
|
||||||
|
where
|
||||||
|
C: CosmWasmClient + Sync,
|
||||||
|
{
|
||||||
|
self.client.get_tx(id).await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn get_total_supply(&self) -> Result<Vec<Coin>, NymdError>
|
pub async fn get_total_supply(&self) -> Result<Vec<Coin>, NymdError>
|
||||||
where
|
where
|
||||||
C: CosmWasmClient + Sync,
|
C: CosmWasmClient + Sync,
|
||||||
|
|||||||
@@ -3,7 +3,10 @@
|
|||||||
|
|
||||||
use crate::validator_api::error::ValidatorAPIError;
|
use crate::validator_api::error::ValidatorAPIError;
|
||||||
use crate::validator_api::routes::{CORE_STATUS_COUNT, SINCE_ARG};
|
use crate::validator_api::routes::{CORE_STATUS_COUNT, SINCE_ARG};
|
||||||
use coconut_interface::{BlindSignRequestBody, BlindedSignatureResponse, VerificationKeyResponse};
|
use coconut_interface::{
|
||||||
|
BlindSignRequestBody, BlindedSignatureResponse, Credential, VerificationKeyResponse,
|
||||||
|
VerifyCredentialResponse,
|
||||||
|
};
|
||||||
use mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixNodeBond};
|
use mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixNodeBond};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@@ -270,6 +273,18 @@ impl Client {
|
|||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn verify_credential(
|
||||||
|
&self,
|
||||||
|
request_body: &Credential,
|
||||||
|
) -> Result<VerifyCredentialResponse, ValidatorAPIError> {
|
||||||
|
self.post_validator_api(
|
||||||
|
&[routes::API_VERSION, routes::COCONUT_VERIFY_CREDENTIAL],
|
||||||
|
NO_PARAMS,
|
||||||
|
request_body,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// utility function that should solve the double slash problem in validator API forever.
|
// utility function that should solve the double slash problem in validator API forever.
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ pub const REWARDED: &str = "rewarded";
|
|||||||
|
|
||||||
pub const COCONUT_BLIND_SIGN: &str = "blind-sign";
|
pub const COCONUT_BLIND_SIGN: &str = "blind-sign";
|
||||||
pub const COCONUT_VERIFICATION_KEY: &str = "verification-key";
|
pub const COCONUT_VERIFICATION_KEY: &str = "verification-key";
|
||||||
|
pub const COCONUT_VERIFY_CREDENTIAL: &str = "verify-credential";
|
||||||
|
|
||||||
pub const STATUS_ROUTES: &str = "status";
|
pub const STATUS_ROUTES: &str = "status";
|
||||||
pub const MIXNODE: &str = "mixnode";
|
pub const MIXNODE: &str = "mixnode";
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use getset::{CopyGetters, Getters};
|
use getset::{CopyGetters, Getters, Setters};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub use nymcoconut::*;
|
pub use nymcoconut::*;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Getters, CopyGetters, Clone)]
|
#[derive(Serialize, Deserialize, Getters, CopyGetters, Setters, Clone)]
|
||||||
pub struct Credential {
|
pub struct Credential {
|
||||||
#[getset(get = "pub")]
|
#[getset(get = "pub")]
|
||||||
n_params: u32,
|
n_params: u32,
|
||||||
@@ -15,6 +15,8 @@ pub struct Credential {
|
|||||||
public_attributes: Vec<Vec<u8>>,
|
public_attributes: Vec<Vec<u8>>,
|
||||||
#[getset(get = "pub")]
|
#[getset(get = "pub")]
|
||||||
signature: Signature,
|
signature: Signature,
|
||||||
|
#[getset(get = "pub", set = "pub")]
|
||||||
|
proposal_id: u64,
|
||||||
}
|
}
|
||||||
impl Credential {
|
impl Credential {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
@@ -22,12 +24,14 @@ impl Credential {
|
|||||||
theta: Theta,
|
theta: Theta,
|
||||||
public_attributes: Vec<Vec<u8>>,
|
public_attributes: Vec<Vec<u8>>,
|
||||||
signature: &Signature,
|
signature: &Signature,
|
||||||
|
proposal_id: u64,
|
||||||
) -> Credential {
|
) -> Credential {
|
||||||
Credential {
|
Credential {
|
||||||
n_params,
|
n_params,
|
||||||
theta,
|
theta,
|
||||||
public_attributes,
|
public_attributes,
|
||||||
signature: *signature,
|
signature: *signature,
|
||||||
|
proposal_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,11 +41,13 @@ impl Credential {
|
|||||||
|
|
||||||
pub fn verify(&self, verification_key: &VerificationKey) -> bool {
|
pub fn verify(&self, verification_key: &VerificationKey) -> bool {
|
||||||
let params = Parameters::new(self.n_params).unwrap();
|
let params = Parameters::new(self.n_params).unwrap();
|
||||||
let public_attributes = self
|
let mut public_attributes = vec![];
|
||||||
.public_attributes
|
for attr in &self.public_attributes {
|
||||||
.iter()
|
match Attribute::try_from_byte_slice(attr) {
|
||||||
.map(hash_to_scalar)
|
Ok(attr) => public_attributes.push(attr),
|
||||||
.collect::<Vec<Attribute>>();
|
Err(_) => return false,
|
||||||
|
}
|
||||||
|
}
|
||||||
nymcoconut::verify_credential(¶ms, verification_key, &self.theta, &public_attributes)
|
nymcoconut::verify_credential(¶ms, verification_key, &self.theta, &public_attributes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,6 +94,7 @@ pub struct BlindSignRequestBody {
|
|||||||
public_attributes: Vec<String>,
|
public_attributes: Vec<String>,
|
||||||
#[getset(get = "pub")]
|
#[getset(get = "pub")]
|
||||||
total_params: u32,
|
total_params: u32,
|
||||||
|
tx_hash: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BlindSignRequestBody {
|
impl BlindSignRequestBody {
|
||||||
@@ -96,6 +103,7 @@ impl BlindSignRequestBody {
|
|||||||
public_key: &nymcoconut::PublicKey,
|
public_key: &nymcoconut::PublicKey,
|
||||||
public_attributes: &[Attribute],
|
public_attributes: &[Attribute],
|
||||||
total_params: u32,
|
total_params: u32,
|
||||||
|
tx_hash: String,
|
||||||
) -> BlindSignRequestBody {
|
) -> BlindSignRequestBody {
|
||||||
BlindSignRequestBody {
|
BlindSignRequestBody {
|
||||||
blind_sign_request: blind_sign_request.clone(),
|
blind_sign_request: blind_sign_request.clone(),
|
||||||
@@ -105,6 +113,7 @@ impl BlindSignRequestBody {
|
|||||||
.map(|attr| attr.to_bs58())
|
.map(|attr| attr.to_bs58())
|
||||||
.collect(),
|
.collect(),
|
||||||
total_params,
|
total_params,
|
||||||
|
tx_hash,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,6 +123,10 @@ impl BlindSignRequestBody {
|
|||||||
.map(|x| Attribute::try_from_bs58(x).unwrap())
|
.map(|x| Attribute::try_from_bs58(x).unwrap())
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn tx_hash(&self) -> &str {
|
||||||
|
&self.tx_hash
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
@@ -137,3 +150,8 @@ impl VerificationKeyResponse {
|
|||||||
VerificationKeyResponse { key }
|
VerificationKeyResponse { key }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct VerifyCredentialResponse {
|
||||||
|
pub response: bool,
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ use url::Url;
|
|||||||
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
|
|
||||||
use super::utils::{obtain_aggregate_signature, prepare_credential_for_spending};
|
use super::utils::{
|
||||||
|
obtain_aggregate_signature, obtain_aggregate_verify_credential, prepare_credential_for_spending,
|
||||||
|
};
|
||||||
|
|
||||||
pub const PUBLIC_ATTRIBUTES: u32 = 2;
|
pub const PUBLIC_ATTRIBUTES: u32 = 2;
|
||||||
pub const PRIVATE_ATTRIBUTES: u32 = 2;
|
pub const PRIVATE_ATTRIBUTES: u32 = 2;
|
||||||
@@ -46,11 +48,26 @@ pub async fn obtain_signature(
|
|||||||
params: &Parameters,
|
params: &Parameters,
|
||||||
attributes: &BandwidthVoucherAttributes,
|
attributes: &BandwidthVoucherAttributes,
|
||||||
validators: &[Url],
|
validators: &[Url],
|
||||||
|
tx_hash: String,
|
||||||
) -> Result<Signature, Error> {
|
) -> Result<Signature, Error> {
|
||||||
let public_attributes = attributes.get_public_attributes();
|
let public_attributes = attributes.get_public_attributes();
|
||||||
let private_attributes = attributes.get_private_attributes();
|
let private_attributes = attributes.get_private_attributes();
|
||||||
|
|
||||||
obtain_aggregate_signature(params, &public_attributes, &private_attributes, validators).await
|
obtain_aggregate_signature(
|
||||||
|
params,
|
||||||
|
&public_attributes,
|
||||||
|
&private_attributes,
|
||||||
|
validators,
|
||||||
|
tx_hash,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn verify_credential_remote(
|
||||||
|
validators: &[Url],
|
||||||
|
credential: Credential,
|
||||||
|
) -> Result<bool, Error> {
|
||||||
|
obtain_aggregate_verify_credential(validators, credential).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prepare_for_spending(
|
pub fn prepare_for_spending(
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
use coconut_interface::{
|
use coconut_interface::{
|
||||||
aggregate_signature_shares, aggregate_verification_keys, prepare_blind_sign,
|
aggregate_signature_shares, aggregate_verification_keys, prepare_blind_sign,
|
||||||
prove_bandwidth_credential, Attribute, BlindSignRequestBody, Credential, Parameters, Signature,
|
prove_bandwidth_credential, Attribute, Base58, BlindSignRequest, BlindSignRequestBody,
|
||||||
SignatureShare, VerificationKey,
|
Credential, ElGamalKeyPair, Parameters, Signature, SignatureShare, VerificationKey,
|
||||||
};
|
};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
@@ -47,17 +47,41 @@ pub async fn obtain_aggregate_verification_key(
|
|||||||
let mut client = validator_client::ApiClient::new(validators[0].clone());
|
let mut client = validator_client::ApiClient::new(validators[0].clone());
|
||||||
let response = client.get_coconut_verification_key().await?;
|
let response = client.get_coconut_verification_key().await?;
|
||||||
|
|
||||||
indices.push(0);
|
indices.push(1);
|
||||||
shares.push(response.key);
|
shares.push(response.key);
|
||||||
|
|
||||||
for (id, validator_url) in validators.iter().enumerate().skip(1) {
|
for (id, validator_url) in validators.iter().enumerate().skip(1) {
|
||||||
client.change_validator_api(validator_url.clone());
|
client.change_validator_api(validator_url.clone());
|
||||||
let response = client.get_coconut_verification_key().await?;
|
let response = client.get_coconut_verification_key().await?;
|
||||||
indices.push(id as u64);
|
indices.push((id + 1) as u64);
|
||||||
shares.push(response.key);
|
shares.push(response.key);
|
||||||
}
|
}
|
||||||
|
let ret = aggregate_verification_keys(&shares, Some(&indices))?;
|
||||||
|
|
||||||
Ok(aggregate_verification_keys(&shares, Some(&indices))?)
|
Ok(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn obtain_aggregate_verify_credential(
|
||||||
|
validators: &[Url],
|
||||||
|
credential: Credential,
|
||||||
|
) -> Result<bool, Error> {
|
||||||
|
if validators.is_empty() {
|
||||||
|
return Err(Error::NoValidatorsAvailable);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut ret = true;
|
||||||
|
|
||||||
|
let mut client = validator_client::ApiClient::new(validators[0].clone());
|
||||||
|
let response = client.verify_credential(&credential).await?;
|
||||||
|
ret &= response.response;
|
||||||
|
|
||||||
|
for validator_url in validators.iter().skip(1) {
|
||||||
|
client.change_validator_api(validator_url.clone());
|
||||||
|
let response = client.verify_credential(&credential).await?;
|
||||||
|
ret &= response.response;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn obtain_partial_credential(
|
async fn obtain_partial_credential(
|
||||||
@@ -66,20 +90,16 @@ async fn obtain_partial_credential(
|
|||||||
private_attributes: &[Attribute],
|
private_attributes: &[Attribute],
|
||||||
client: &validator_client::ApiClient,
|
client: &validator_client::ApiClient,
|
||||||
validator_vk: &VerificationKey,
|
validator_vk: &VerificationKey,
|
||||||
|
blind_sign_request: &BlindSignRequest,
|
||||||
|
elgamal_keypair: &ElGamalKeyPair,
|
||||||
|
tx_hash: String,
|
||||||
) -> Result<Signature, Error> {
|
) -> Result<Signature, Error> {
|
||||||
let elgamal_keypair = coconut_interface::elgamal_keygen(params);
|
|
||||||
let blind_sign_request = prepare_blind_sign(
|
|
||||||
params,
|
|
||||||
&elgamal_keypair,
|
|
||||||
private_attributes,
|
|
||||||
public_attributes,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let blind_sign_request_body = BlindSignRequestBody::new(
|
let blind_sign_request_body = BlindSignRequestBody::new(
|
||||||
&blind_sign_request,
|
blind_sign_request,
|
||||||
elgamal_keypair.public_key(),
|
elgamal_keypair.public_key(),
|
||||||
public_attributes,
|
public_attributes,
|
||||||
(public_attributes.len() + private_attributes.len()) as u32,
|
(public_attributes.len() + private_attributes.len()) as u32,
|
||||||
|
tx_hash,
|
||||||
);
|
);
|
||||||
|
|
||||||
let blinded_signature = client
|
let blinded_signature = client
|
||||||
@@ -104,6 +124,7 @@ pub async fn obtain_aggregate_signature(
|
|||||||
public_attributes: &[Attribute],
|
public_attributes: &[Attribute],
|
||||||
private_attributes: &[Attribute],
|
private_attributes: &[Attribute],
|
||||||
validators: &[Url],
|
validators: &[Url],
|
||||||
|
tx_hash: String,
|
||||||
) -> Result<Signature, Error> {
|
) -> Result<Signature, Error> {
|
||||||
if validators.is_empty() {
|
if validators.is_empty() {
|
||||||
return Err(Error::NoValidatorsAvailable);
|
return Err(Error::NoValidatorsAvailable);
|
||||||
@@ -116,15 +137,26 @@ pub async fn obtain_aggregate_signature(
|
|||||||
let validator_partial_vk = client.get_coconut_verification_key().await?;
|
let validator_partial_vk = client.get_coconut_verification_key().await?;
|
||||||
validators_partial_vks.push(validator_partial_vk.key.clone());
|
validators_partial_vks.push(validator_partial_vk.key.clone());
|
||||||
|
|
||||||
|
let elgamal_keypair = coconut_interface::elgamal_keygen(params);
|
||||||
|
let blind_sign_request = prepare_blind_sign(
|
||||||
|
params,
|
||||||
|
&elgamal_keypair,
|
||||||
|
private_attributes,
|
||||||
|
public_attributes,
|
||||||
|
)?;
|
||||||
|
|
||||||
let first = obtain_partial_credential(
|
let first = obtain_partial_credential(
|
||||||
params,
|
params,
|
||||||
public_attributes,
|
public_attributes,
|
||||||
private_attributes,
|
private_attributes,
|
||||||
&client,
|
&client,
|
||||||
&validator_partial_vk.key,
|
&validator_partial_vk.key,
|
||||||
|
&blind_sign_request,
|
||||||
|
&elgamal_keypair,
|
||||||
|
tx_hash.clone(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
shares.push(SignatureShare::new(first, 0));
|
shares.push(SignatureShare::new(first, 1));
|
||||||
|
|
||||||
for (id, validator_url) in validators.iter().enumerate().skip(1) {
|
for (id, validator_url) in validators.iter().enumerate().skip(1) {
|
||||||
client.change_validator_api(validator_url.clone());
|
client.change_validator_api(validator_url.clone());
|
||||||
@@ -136,9 +168,12 @@ pub async fn obtain_aggregate_signature(
|
|||||||
private_attributes,
|
private_attributes,
|
||||||
&client,
|
&client,
|
||||||
&validator_partial_vk.key,
|
&validator_partial_vk.key,
|
||||||
|
&blind_sign_request,
|
||||||
|
&elgamal_keypair,
|
||||||
|
tx_hash.clone(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
let share = SignatureShare::new(signature, id as u64);
|
let share = SignatureShare::new(signature, (id + 1) as u64);
|
||||||
shares.push(share)
|
shares.push(share)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,11 +182,12 @@ pub async fn obtain_aggregate_signature(
|
|||||||
attributes.extend_from_slice(public_attributes);
|
attributes.extend_from_slice(public_attributes);
|
||||||
|
|
||||||
let mut indices: Vec<u64> = Vec::with_capacity(validators_partial_vks.len());
|
let mut indices: Vec<u64> = Vec::with_capacity(validators_partial_vks.len());
|
||||||
for i in 1..validators_partial_vks.len() {
|
for i in 0..validators_partial_vks.len() {
|
||||||
indices.push(i as u64);
|
indices.push((i + 1) as u64);
|
||||||
}
|
}
|
||||||
let verification_key =
|
let verification_key =
|
||||||
aggregate_verification_keys(&validators_partial_vks, Some(indices.as_ref()))?;
|
aggregate_verification_keys(&validators_partial_vks, Some(indices.as_ref()))?;
|
||||||
|
println!("Verification key: {}", verification_key.to_bs58());
|
||||||
|
|
||||||
Ok(aggregate_signature_shares(
|
Ok(aggregate_signature_shares(
|
||||||
params,
|
params,
|
||||||
@@ -183,5 +219,6 @@ pub fn prepare_credential_for_spending(
|
|||||||
theta,
|
theta,
|
||||||
public_attributes,
|
public_attributes,
|
||||||
signature,
|
signature,
|
||||||
|
0,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
extern crate core;
|
||||||
|
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
|
||||||
use bls12_381::Scalar;
|
use bls12_381::Scalar;
|
||||||
|
|
||||||
|
pub use crate::traits::Bytable;
|
||||||
pub use elgamal::elgamal_keygen;
|
pub use elgamal::elgamal_keygen;
|
||||||
pub use elgamal::ElGamalKeyPair;
|
pub use elgamal::ElGamalKeyPair;
|
||||||
pub use elgamal::PublicKey;
|
pub use elgamal::PublicKey;
|
||||||
@@ -28,8 +31,6 @@ pub use scheme::SignatureShare;
|
|||||||
pub use traits::Base58;
|
pub use traits::Base58;
|
||||||
pub use utils::hash_to_scalar;
|
pub use utils::hash_to_scalar;
|
||||||
|
|
||||||
use crate::traits::Bytable;
|
|
||||||
|
|
||||||
pub mod elgamal;
|
pub mod elgamal;
|
||||||
mod error;
|
mod error;
|
||||||
mod impls;
|
mod impls;
|
||||||
|
|||||||
@@ -206,10 +206,17 @@ pub fn verify_credential(
|
|||||||
public_attributes: &[Attribute],
|
public_attributes: &[Attribute],
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if public_attributes.len() + theta.pi_v.private_attributes_len() > verification_key.beta.len() {
|
if public_attributes.len() + theta.pi_v.private_attributes_len() > verification_key.beta.len() {
|
||||||
|
println!(
|
||||||
|
"Len fail: {} + {} > {}",
|
||||||
|
public_attributes.len(),
|
||||||
|
theta.pi_v.private_attributes_len(),
|
||||||
|
verification_key.beta.len()
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !theta.verify_proof(params, verification_key) {
|
if !theta.verify_proof(params, verification_key) {
|
||||||
|
println!("Proof fail");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,12 +237,14 @@ pub fn verify_credential(
|
|||||||
theta.blinded_message + signed_public_attributes
|
theta.blinded_message + signed_public_attributes
|
||||||
};
|
};
|
||||||
|
|
||||||
check_bilinear_pairing(
|
let ret = check_bilinear_pairing(
|
||||||
&theta.credential.0.to_affine(),
|
&theta.credential.0.to_affine(),
|
||||||
&G2Prepared::from(kappa.to_affine()),
|
&G2Prepared::from(kappa.to_affine()),
|
||||||
&(theta.credential.1).to_affine(),
|
&(theta.credential.1).to_affine(),
|
||||||
params.prepared_miller_g2(),
|
params.prepared_miller_g2(),
|
||||||
) && !bool::from(theta.credential.0.is_identity())
|
);
|
||||||
|
println!("Ret value {}", ret);
|
||||||
|
ret && !bool::from(theta.credential.0.is_identity())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used in tests only
|
// Used in tests only
|
||||||
|
|||||||
@@ -8,11 +8,9 @@ edition = "2021"
|
|||||||
[lib]
|
[lib]
|
||||||
crate-type = ["cdylib", "rlib"]
|
crate-type = ["cdylib", "rlib"]
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
config = { path = "../../common/config"}
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bandwidth-claim-contract = { path = "../../common/bandwidth-claim-contract" }
|
bandwidth-claim-contract = { path = "../../common/bandwidth-claim-contract" }
|
||||||
|
config = { path = "../../common/config"}
|
||||||
|
|
||||||
cosmwasm-std = "1.0.0-beta3"
|
cosmwasm-std = "1.0.0-beta3"
|
||||||
cosmwasm-storage = "1.0.0-beta3"
|
cosmwasm-storage = "1.0.0-beta3"
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use config::defaults::DENOM;
|
||||||
|
|
||||||
use cosmwasm_std::{StdError, VerificationError};
|
use cosmwasm_std::{StdError, VerificationError};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
@@ -24,4 +26,16 @@ pub enum ContractError {
|
|||||||
|
|
||||||
#[error("The payment is not properly signed")]
|
#[error("The payment is not properly signed")]
|
||||||
BadSignature,
|
BadSignature,
|
||||||
|
|
||||||
|
#[error("Received multiple coin types")]
|
||||||
|
MultipleDenoms,
|
||||||
|
|
||||||
|
#[error("No coin was sent for voucher")]
|
||||||
|
NoCoin,
|
||||||
|
|
||||||
|
#[error("Wrong coin denomination, you must send {}", DENOM)]
|
||||||
|
WrongDenom,
|
||||||
|
|
||||||
|
#[error("The sender is not authorized to perform this action")]
|
||||||
|
Unauthorized,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,10 @@ pub fn execute(
|
|||||||
) -> Result<Response, ContractError> {
|
) -> Result<Response, ContractError> {
|
||||||
match msg {
|
match msg {
|
||||||
ExecuteMsg::LinkPayment { data } => transactions::link_payment(deps, env, info, data),
|
ExecuteMsg::LinkPayment { data } => transactions::link_payment(deps, env, info, data),
|
||||||
|
ExecuteMsg::BuyBandwidth {} => transactions::buy_bandwidth(deps, env, info),
|
||||||
|
ExecuteMsg::SpendCredential { amount } => {
|
||||||
|
transactions::spend_credential(deps, env, info, amount)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ use bandwidth_claim_contract::payment::Payment;
|
|||||||
// buckets
|
// buckets
|
||||||
const PREFIX_PAYMENTS: &[u8] = b"payments";
|
const PREFIX_PAYMENTS: &[u8] = b"payments";
|
||||||
const PREFIX_STATUS: &[u8] = b"status";
|
const PREFIX_STATUS: &[u8] = b"status";
|
||||||
|
const PREFIX_COCONUT: &[u8] = b"coconut";
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||||
pub enum Status {
|
pub enum Status {
|
||||||
@@ -31,6 +32,14 @@ pub fn status(storage: &mut dyn Storage) -> Bucket<'_, Status> {
|
|||||||
bucket(storage, PREFIX_STATUS)
|
bucket(storage, PREFIX_STATUS)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn coconut(storage: &mut dyn Storage) -> Bucket<'_, Payment> {
|
||||||
|
bucket(storage, PREFIX_COCONUT)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn coconut_read(storage: &dyn Storage) -> ReadonlyBucket<'_, Payment> {
|
||||||
|
bucket_read(storage, PREFIX_COCONUT)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use cosmwasm_std::{DepsMut, Env, MessageInfo, Response};
|
use cosmwasm_std::{Addr, BankMsg, Coin, DepsMut, Env, Event, MessageInfo, Response};
|
||||||
|
|
||||||
use crate::error::ContractError;
|
use crate::error::ContractError;
|
||||||
use crate::storage::{payments, status, Status};
|
use crate::storage::{coconut, payments, status, Status};
|
||||||
|
use bandwidth_claim_contract::events::{VOUCHER_ACQUIRED_EVENT_TYPE, VOUCHER_VALUE};
|
||||||
use bandwidth_claim_contract::payment::{LinkPaymentData, Payment};
|
use bandwidth_claim_contract::payment::{LinkPaymentData, Payment};
|
||||||
|
use config::defaults::DENOM;
|
||||||
|
|
||||||
pub(crate) fn link_payment(
|
pub(crate) fn link_payment(
|
||||||
deps: DepsMut<'_>,
|
deps: DepsMut<'_>,
|
||||||
@@ -44,6 +46,43 @@ pub(crate) fn link_payment(
|
|||||||
Ok(Response::default())
|
Ok(Response::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn buy_bandwidth(
|
||||||
|
_deps: DepsMut<'_>,
|
||||||
|
_env: Env,
|
||||||
|
info: MessageInfo,
|
||||||
|
) -> Result<Response, ContractError> {
|
||||||
|
if info.funds.is_empty() {
|
||||||
|
return Err(ContractError::NoCoin);
|
||||||
|
}
|
||||||
|
if info.funds.len() > 1 {
|
||||||
|
return Err(ContractError::MultipleDenoms);
|
||||||
|
}
|
||||||
|
if info.funds[0].denom != DENOM {
|
||||||
|
return Err(ContractError::WrongDenom);
|
||||||
|
}
|
||||||
|
|
||||||
|
let voucher_value = info.funds.last().unwrap();
|
||||||
|
let event =
|
||||||
|
Event::new(VOUCHER_ACQUIRED_EVENT_TYPE).add_attribute(VOUCHER_VALUE, voucher_value.amount);
|
||||||
|
Ok(Response::new().add_event(event))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn spend_credential(
|
||||||
|
_deps: DepsMut<'_>,
|
||||||
|
_env: Env,
|
||||||
|
info: MessageInfo,
|
||||||
|
amount: u64,
|
||||||
|
) -> Result<Response, ContractError> {
|
||||||
|
if info.sender != Addr::unchecked(String::from("nymt1qwlgtx52gsdu7dtp0cekka5zehdl0uj3vqx3jd")) {
|
||||||
|
return Err(ContractError::Unauthorized);
|
||||||
|
}
|
||||||
|
let return_tokens = BankMsg::Send {
|
||||||
|
to_address: String::from("nymt1t6p4dl8nnlftvehz3jsklrd0aw458p4l6n9n4t"),
|
||||||
|
amount: vec![Coin::new(amount as u128, DENOM)],
|
||||||
|
};
|
||||||
|
Ok(Response::new().add_message(return_tokens))
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ rust-version = "1.56"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
cw3-flex-multisig = "0.12.1"
|
||||||
|
cw3 = "0.12.1"
|
||||||
|
bip39 = "1.0.1"
|
||||||
clap = "2.33.0"
|
clap = "2.33.0"
|
||||||
dirs = "3.0"
|
dirs = "3.0"
|
||||||
dotenv = "0.15.0"
|
dotenv = "0.15.0"
|
||||||
@@ -47,6 +50,7 @@ config = { path = "../common/config" }
|
|||||||
crypto = { path="../common/crypto" }
|
crypto = { path="../common/crypto" }
|
||||||
gateway-client = { path="../common/client-libs/gateway-client" }
|
gateway-client = { path="../common/client-libs/gateway-client" }
|
||||||
mixnet-contract-common = { path= "../common/cosmwasm-smart-contracts/mixnet-contract" }
|
mixnet-contract-common = { path= "../common/cosmwasm-smart-contracts/mixnet-contract" }
|
||||||
|
bandwidth-claim-contract = { path= "../common/bandwidth-claim-contract" }
|
||||||
nymsphinx = { path="../common/nymsphinx" }
|
nymsphinx = { path="../common/nymsphinx" }
|
||||||
topology = { path="../common/topology" }
|
topology = { path="../common/topology" }
|
||||||
validator-api-requests = { path = "validator-api-requests" }
|
validator-api-requests = { path = "validator-api-requests" }
|
||||||
|
|||||||
@@ -1,15 +1,23 @@
|
|||||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use bandwidth_claim_contract::events::{VOUCHER_ACQUIRED_EVENT_TYPE, VOUCHER_VALUE};
|
||||||
|
use bip39::Mnemonic;
|
||||||
use coconut_interface::{
|
use coconut_interface::{
|
||||||
elgamal::PublicKey, Attribute, BlindSignRequest, BlindSignRequestBody, BlindedSignature,
|
elgamal::PublicKey, Attribute, Base58, BlindSignRequest, BlindSignRequestBody,
|
||||||
BlindedSignatureResponse, KeyPair, Parameters, VerificationKeyResponse,
|
BlindedSignature, BlindedSignatureResponse, Credential, KeyPair, Parameters, VerificationKey,
|
||||||
|
VerificationKeyResponse, VerifyCredentialResponse,
|
||||||
};
|
};
|
||||||
use config::defaults::VALIDATOR_API_VERSION;
|
use config::defaults::VALIDATOR_API_VERSION;
|
||||||
|
use cw3_flex_multisig::msg::ExecuteMsg;
|
||||||
use getset::{CopyGetters, Getters};
|
use getset::{CopyGetters, Getters};
|
||||||
use rocket::fairing::AdHoc;
|
use rocket::fairing::AdHoc;
|
||||||
use rocket::serde::json::Json;
|
use rocket::serde::json::Json;
|
||||||
use rocket::State;
|
use rocket::State;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use url::Url;
|
||||||
|
use validator_client::nymd::tx::Hash;
|
||||||
|
use validator_client::nymd::{AccountId, NymdClient};
|
||||||
|
|
||||||
#[derive(Getters, CopyGetters, Debug)]
|
#[derive(Getters, CopyGetters, Debug)]
|
||||||
pub(crate) struct InternalSignRequest {
|
pub(crate) struct InternalSignRequest {
|
||||||
@@ -44,7 +52,11 @@ impl InternalSignRequest {
|
|||||||
rocket.manage(key_pair).mount(
|
rocket.manage(key_pair).mount(
|
||||||
// this format! is so ugly...
|
// this format! is so ugly...
|
||||||
format!("/{}", VALIDATOR_API_VERSION),
|
format!("/{}", VALIDATOR_API_VERSION),
|
||||||
routes![post_blind_sign, get_verification_key],
|
routes![
|
||||||
|
post_blind_sign,
|
||||||
|
get_verification_key,
|
||||||
|
post_verify_credential
|
||||||
|
],
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -69,6 +81,50 @@ pub async fn post_blind_sign(
|
|||||||
key_pair: &State<KeyPair>,
|
key_pair: &State<KeyPair>,
|
||||||
) -> Json<BlindedSignatureResponse> {
|
) -> Json<BlindedSignatureResponse> {
|
||||||
debug!("{:?}", blind_sign_request_body);
|
debug!("{:?}", blind_sign_request_body);
|
||||||
|
let nymd_url = Url::from_str("http://127.0.0.1:26657").unwrap();
|
||||||
|
let mnemonic = Mnemonic::from_str(&"have armor behind appear labor choose fire erase arrive slice mother acid second rely exhibit grief soul super record useless antique excite ocean walnut").unwrap();
|
||||||
|
let nymd_client = NymdClient::connect_with_mnemonic(
|
||||||
|
config::defaults::all::Network::SANDBOX,
|
||||||
|
nymd_url.as_ref(),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
mnemonic,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.expect("Could not create nymd client");
|
||||||
|
println!("Looking at tx {}", blind_sign_request_body.0.tx_hash());
|
||||||
|
let response = nymd_client
|
||||||
|
.get_tx(Hash::from_str(blind_sign_request_body.0.tx_hash()).unwrap())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
println!("Events: {:?}", response.tx_result.events);
|
||||||
|
let bandwidth_str = response
|
||||||
|
.tx_result
|
||||||
|
.events
|
||||||
|
.iter()
|
||||||
|
.filter(|event| event.type_str == format!("wasm-{}", VOUCHER_ACQUIRED_EVENT_TYPE))
|
||||||
|
.map(|event| {
|
||||||
|
event
|
||||||
|
.attributes
|
||||||
|
.iter()
|
||||||
|
.filter(|tag| tag.key.as_ref() == VOUCHER_VALUE)
|
||||||
|
.last()
|
||||||
|
.unwrap()
|
||||||
|
.value
|
||||||
|
.as_ref()
|
||||||
|
})
|
||||||
|
.last()
|
||||||
|
.unwrap();
|
||||||
|
println!("Bandwidth str: {}", bandwidth_str);
|
||||||
|
let acuired_bandwidth = Attribute::from(u64::from_str(bandwidth_str).unwrap());
|
||||||
|
let requested_bandwidth = blind_sign_request_body.0.public_attributes()[0];
|
||||||
|
if acuired_bandwidth != requested_bandwidth {
|
||||||
|
panic!(
|
||||||
|
"Bandwidth value mismatch: {} vs {}",
|
||||||
|
acuired_bandwidth, requested_bandwidth
|
||||||
|
);
|
||||||
|
}
|
||||||
let internal_request = InternalSignRequest::new(
|
let internal_request = InternalSignRequest::new(
|
||||||
*blind_sign_request_body.total_params(),
|
*blind_sign_request_body.total_params(),
|
||||||
blind_sign_request_body.public_attributes(),
|
blind_sign_request_body.public_attributes(),
|
||||||
@@ -83,3 +139,56 @@ pub async fn post_blind_sign(
|
|||||||
pub async fn get_verification_key(key_pair: &State<KeyPair>) -> Json<VerificationKeyResponse> {
|
pub async fn get_verification_key(key_pair: &State<KeyPair>) -> Json<VerificationKeyResponse> {
|
||||||
Json(VerificationKeyResponse::new(key_pair.verification_key()))
|
Json(VerificationKeyResponse::new(key_pair.verification_key()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[post("/verify-credential", data = "<verify_credential_body>")]
|
||||||
|
pub async fn post_verify_credential(
|
||||||
|
verify_credential_body: Json<Credential>,
|
||||||
|
key_pair: &State<KeyPair>,
|
||||||
|
) -> Json<VerifyCredentialResponse> {
|
||||||
|
println!(
|
||||||
|
"Using verification key: {:?}",
|
||||||
|
key_pair.verification_key().to_bs58()
|
||||||
|
);
|
||||||
|
let aggregated_verification_key = VerificationKey::try_from_bs58("4uTfTzJ1ViDLaWhDkZCHPsM9uv6GqDJ8bfHu6eKuQ5Zzan9KacaNCMuwtHDTpmZyfFHWuqi5cZL5HsDJ6RewGMyG13TTTn8fXdvs4TeuukTP5Kdn7ZpLEZmwra5gFZj3nokqpB6Kk2T88WwDVq5kHgtBikcG6N5fqJWmyb8TNhTjB3WQ87R4x5TbioLPRTRw9w4Ho2zgdGH1X3F99VKGWaYSNXTP22ganxCnd5Yjo3ARbFC21hc4qH7c4Y8EK4X8jML6MJTjbTpFQ5u6evib35knWf4rwm5Rtuoh8SgixmV8J5dovsJ4FbH9oB2PuWUf7hPThfY9ipqoefoFiMtGwT8wvNkB9zmGJqNDHUohoaZniBYSge3XYx8P53D8y1gkZVwTdL9TxRNpV3SoyLvXBWZL8Vv4tqEByhycKWYhgrmLDf5w8VS9riSqgJC2eqTDgNVxZrm8XZj2wArShFixsqiJHnhDzcMkUYx2vnEYdfE6FHYHncaoq58i32J9TaWM9sgvAnubcRPLofU8F45aR682tBYtEn3uNzxYEhgjuTmmiKuUifV79FBco3td8FTbwxz6yKxoWk3yJhPBo3fPXQoZFxDfB6CE5yp4ma1D7qdzYV1kJFcK7cCwqRZg6AveybdW9cDPMyPPzG2CqFSJMZvKKTB").unwrap();
|
||||||
|
let response = verify_credential_body
|
||||||
|
.0
|
||||||
|
.verify(&aggregated_verification_key);
|
||||||
|
if !response {
|
||||||
|
return Json(VerifyCredentialResponse { response });
|
||||||
|
}
|
||||||
|
let mnemonic = if std::env::var("ROCKET_PORT") == Ok("8081".to_string()) {
|
||||||
|
"have armor behind appear labor choose fire erase arrive slice mother acid second rely exhibit grief soul super record useless antique excite ocean walnut"
|
||||||
|
} else if std::env::var("ROCKET_PORT") == Ok("8082".to_string()) {
|
||||||
|
"inner luggage start square fabric ritual cereal engine winner tiny exile frozen end cherry loan humble laundry desk blur vicious word amount remove praise"
|
||||||
|
} else {
|
||||||
|
"hat pulse impulse prosper name rose auction grape stone leader book provide discover exchange drift story parent barely novel giggle deposit dizzy recipe where"
|
||||||
|
};
|
||||||
|
let mnemonic = Mnemonic::from_str(mnemonic).unwrap();
|
||||||
|
let nymd_url = Url::from_str("http://127.0.0.1:26657").unwrap();
|
||||||
|
let nymd_client = NymdClient::connect_with_mnemonic(
|
||||||
|
config::defaults::all::Network::SANDBOX,
|
||||||
|
nymd_url.as_ref(),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
mnemonic,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.expect("Could not create nymd client");
|
||||||
|
let req = ExecuteMsg::Vote {
|
||||||
|
proposal_id: *verify_credential_body.0.proposal_id(),
|
||||||
|
vote: cw3::Vote::Yes,
|
||||||
|
};
|
||||||
|
nymd_client
|
||||||
|
.execute(
|
||||||
|
&AccountId::from_str("nymt1qwlgtx52gsdu7dtp0cekka5zehdl0uj3vqx3jd").unwrap(),
|
||||||
|
&req,
|
||||||
|
Default::default(),
|
||||||
|
"",
|
||||||
|
vec![],
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
println!("Sending response: {}", response);
|
||||||
|
Json(VerifyCredentialResponse { response })
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user