From 9e8f550e6d6d070ad2c6d5f94438b3b6e87b4d97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogdan-=C8=98tefan=20Neac=C5=9Fu?= Date: Tue, 29 Mar 2022 15:03:38 +0300 Subject: [PATCH] Feature/signature on deposit (#1151) * Add placeholder client for implementing coconut interactions * Add db for persistance * Add nymd client * Add new coconut-bandwidth contract * Call deposit function * Introduce error handling * Call the old flow of getting a signature * List available tx hashes * Add signed req in body * Save signature received * Add event generation * Checks in validator-api * Fail with error instead of panic in validator-api route * Fix contract address and small bug * Add file db for storing previous signatures * Encrypt and store data in validator-api * Decrypt the received signature * Remove tx hashes after getting credentials * Small listing changes in client * Change response so that it easier to serialize * Error message is sent to client for display * Remove already signed error and return the previous sig * Merge signature with deposit data in client * Entrypoint for getting the encrypted signature * Refactor blinding stuff so that it can be backed up * Backed up the blind sign request * Client can re-request the encrypted signature shares * Update crypto features * Fix clippy * Activate instantiate test and remove unused code * Add tx tests * Add verification key endpoint test * Voucher consistency test * Test for some errors and a race condition on blind signing * Refactor and add client trait for enabling better testing env * Test some more of blind sign * Finished testing all extract_encryption_key paths * Split into function test and endpoint test * Test for correct signature * Test for state functions * Remove print * Test blind_sign endpoint * Test for cached signature endpoint * Stricter types in voucher * Rename signature with partial_bandwidth_credential * Extra route levels * Length check and remove some unused code from coconut interface * Renamed coconut-bandwidth common crate * Renamed verification_key to identity_key * Use const instead of hardcoded values * Use type aliases for crypto algorithms * Remove unused mods, until needed * Remove unneeded unwrap * Fix some coconut issues that were blocking the wasm client build * Move from sled to existing sql database * Update tests for new db type * Fix wasm for coconut too * Remove sled from dependencies --- Cargo.lock | 150 +- Cargo.toml | 2 + clients/client-core/Cargo.toml | 2 +- clients/credential/Cargo.lock | 3453 +++++++++++++++++ clients/credential/Cargo.toml | 29 + clients/credential/src/client.rs | 69 + clients/credential/src/commands.rs | 186 + clients/credential/src/error.rs | 41 + clients/credential/src/main.rs | 61 + clients/credential/src/state.rs | 72 + clients/native/Cargo.toml | 2 +- clients/native/src/commands/init.rs | 35 +- clients/socks5/Cargo.toml | 2 +- clients/socks5/src/commands/init.rs | 33 +- common/client-libs/gateway-client/Cargo.toml | 4 +- .../gateway-client/src/bandwidth.rs | 47 +- .../validator-client/src/client.rs | 10 + .../validator-client/src/nymd/mod.rs | 10 + .../src/validator_api/error.rs | 3 + .../validator-client/src/validator_api/mod.rs | 49 +- .../src/validator_api/routes.rs | 4 + common/coconut-interface/Cargo.toml | 4 +- common/coconut-interface/src/error.rs | 20 +- common/coconut-interface/src/lib.rs | 58 +- .../coconut-bandwidth-contract/Cargo.toml | 10 + .../coconut-bandwidth-contract/src/deposit.rs | 34 + .../coconut-bandwidth-contract/src/events.rs | 11 + .../coconut-bandwidth-contract/src/lib.rs | 3 + .../coconut-bandwidth-contract/src/msg.rs | 24 + common/credentials/Cargo.toml | 9 +- common/credentials/src/coconut/bandwidth.rs | 214 +- common/credentials/src/coconut/mod.rs | 1 + common/credentials/src/coconut/params.rs | 15 + common/credentials/src/coconut/utils.rs | 104 +- common/credentials/src/error.rs | 9 +- common/credentials/src/lib.rs | 3 + common/credentials/src/token/bandwidth.rs | 3 - common/network-defaults/src/lib.rs | 2 + common/nymcoconut/src/lib.rs | 3 +- contracts/Cargo.lock | 22 + contracts/Cargo.toml | 2 +- contracts/coconut-bandwidth/Cargo.lock | 867 +++++ contracts/coconut-bandwidth/Cargo.toml | 21 + contracts/coconut-bandwidth/src/error.rs | 26 + contracts/coconut-bandwidth/src/lib.rs | 73 + .../coconut-bandwidth/src/support/mod.rs | 3 + .../coconut-bandwidth/src/support/tests.rs | 19 + .../coconut-bandwidth/src/transactions.rs | 136 + gateway/Cargo.toml | 2 +- gateway/gateway-requests/Cargo.toml | 2 +- validator-api/Cargo.toml | 7 +- .../20220325120000_signed_deposits.sql | 6 + validator-api/src/coconut/client.rs | 35 + validator-api/src/coconut/deposit.rs | 441 +++ validator-api/src/coconut/error.rs | 79 + validator-api/src/coconut/mod.rs | 171 +- validator-api/src/coconut/tests.rs | 510 +++ validator-api/src/config/mod.rs | 2 +- validator-api/src/main.rs | 34 +- validator-api/src/node_status_api/models.rs | 2 +- validator-api/src/storage/manager.rs | 43 + validator-api/src/storage/mod.rs | 44 +- 62 files changed, 7119 insertions(+), 219 deletions(-) create mode 100644 clients/credential/Cargo.lock create mode 100644 clients/credential/Cargo.toml create mode 100644 clients/credential/src/client.rs create mode 100644 clients/credential/src/commands.rs create mode 100644 clients/credential/src/error.rs create mode 100644 clients/credential/src/main.rs create mode 100644 clients/credential/src/state.rs create mode 100644 common/cosmwasm-smart-contracts/coconut-bandwidth-contract/Cargo.toml create mode 100644 common/cosmwasm-smart-contracts/coconut-bandwidth-contract/src/deposit.rs create mode 100644 common/cosmwasm-smart-contracts/coconut-bandwidth-contract/src/events.rs create mode 100644 common/cosmwasm-smart-contracts/coconut-bandwidth-contract/src/lib.rs create mode 100644 common/cosmwasm-smart-contracts/coconut-bandwidth-contract/src/msg.rs create mode 100644 common/credentials/src/coconut/params.rs create mode 100644 contracts/coconut-bandwidth/Cargo.lock create mode 100644 contracts/coconut-bandwidth/Cargo.toml create mode 100644 contracts/coconut-bandwidth/src/error.rs create mode 100644 contracts/coconut-bandwidth/src/lib.rs create mode 100644 contracts/coconut-bandwidth/src/support/mod.rs create mode 100644 contracts/coconut-bandwidth/src/support/tests.rs create mode 100644 contracts/coconut-bandwidth/src/transactions.rs create mode 100644 validator-api/migrations/20220325120000_signed_deposits.sql create mode 100644 validator-api/src/coconut/client.rs create mode 100644 validator-api/src/coconut/deposit.rs create mode 100644 validator-api/src/coconut/error.rs create mode 100644 validator-api/src/coconut/tests.rs diff --git a/Cargo.lock b/Cargo.lock index 7ad3ea4834..e4ddeafe0a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,7 +20,7 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "cipher 0.3.0", "cpufeatures", "ctr 0.8.0", @@ -33,7 +33,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfe0133578c0986e1fe3dfcd4af1cc5b2dd6c3dbf534d69916ce16a2701d40ba" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "cipher 0.4.3", "cpufeatures", ] @@ -313,7 +313,7 @@ dependencies = [ "arrayref", "arrayvec 0.7.2", "cc", - "cfg-if", + "cfg-if 1.0.0", "constant_time_eq", "digest 0.10.3", ] @@ -453,6 +453,12 @@ dependencies = [ "jobserver", ] +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + [[package]] name = "cfg-if" version = "1.0.0" @@ -581,13 +587,23 @@ dependencies = [ "bitflags", ] +[[package]] +name = "coconut-bandwidth-contract-common" +version = "0.1.0" +dependencies = [ + "schemars", + "serde", +] + [[package]] name = "coconut-interface" version = "0.1.0" dependencies = [ + "bs58", "getset", "nymcoconut", "serde", + "thiserror", ] [[package]] @@ -817,7 +833,30 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", +] + +[[package]] +name = "credential" +version = "0.1.0" +dependencies = [ + "async-trait", + "bip39", + "cfg-if 0.1.10", + "clap 3.1.6", + "coconut-bandwidth-contract-common", + "coconut-interface", + "credentials", + "crypto", + "network-defaults", + "pemstore", + "pickledb", + "rand 0.7.3", + "serde", + "thiserror", + "tokio", + "url", + "validator-client", ] [[package]] @@ -826,8 +865,10 @@ version = "0.1.0" dependencies = [ "bls12_381", "coconut-interface", + "cosmrs", "crypto", "network-defaults", + "rand 0.7.3", "thiserror", "url", "validator-client", @@ -875,7 +916,7 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdbfe11fe19ff083c48923cf179540e8cd0535903dc35e178a1fdeeb59aef51f" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "crossbeam-utils", ] @@ -885,7 +926,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "crossbeam-epoch", "crossbeam-utils", ] @@ -897,7 +938,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" dependencies = [ "autocfg 1.1.0", - "cfg-if", + "cfg-if 1.0.0", "crossbeam-utils", "lazy_static", "memoffset", @@ -910,7 +951,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "crossbeam-utils", ] @@ -920,7 +961,7 @@ version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "lazy_static", ] @@ -1132,7 +1173,7 @@ version = "4.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "num_cpus", ] @@ -1380,7 +1421,7 @@ version = "0.8.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] @@ -1588,7 +1629,7 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "crc32fast", "libc", "miniz_oxide", @@ -1814,6 +1855,7 @@ name = "gateway-client" version = "0.1.0" dependencies = [ "coconut-interface", + "cosmrs", "credentials", "crypto", "fluvio-wasm-timer", @@ -1832,6 +1874,7 @@ dependencies = [ "tokio-tungstenite", "tungstenite", "url", + "validator-client", "wasm-bindgen", "wasm-bindgen-futures", "wasm-utils", @@ -1896,7 +1939,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "js-sys", "libc", "wasi 0.9.0+wasi-snapshot-preview1", @@ -1909,7 +1952,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "js-sys", "libc", "wasi 0.10.0+wasi-snapshot-preview1", @@ -2397,7 +2440,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "js-sys", "wasm-bindgen", "web-sys", @@ -2494,7 +2537,7 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "903ae2481bcdfdb7b68e0a9baa4b7c9aff600b9ae2e8e5bb5833b8c91ab851ea" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "ecdsa 0.12.4", "elliptic-curve 0.10.6", "sha2", @@ -2506,7 +2549,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19c3a5e0a0b8450278feda242592512e09f61c72e018b8cd5c859482802daf2d" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "ecdsa 0.13.4", "elliptic-curve 0.11.12", "sec1", @@ -2579,6 +2622,12 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "linked-hash-map" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" + [[package]] name = "lioness" version = "0.1.2" @@ -2606,7 +2655,7 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] @@ -2615,7 +2664,7 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edc5c7d328e32cc4954e8e01193d7f0ef5ab257b5090b70a964e099a36034309" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "generator", "scoped-tls", "serde", @@ -2814,7 +2863,7 @@ dependencies = [ name = "network-defaults" version = "0.1.0" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "hex-literal", "once_cell", "serde", @@ -3079,9 +3128,11 @@ name = "nym-validator-api" version = "0.12.0" dependencies = [ "anyhow", + "async-trait", "attohttpc", - "cfg-if", + "cfg-if 1.0.0", "clap 2.34.0", + "coconut-bandwidth-contract-common", "coconut-interface", "config", "console-subscriber", @@ -3095,6 +3146,7 @@ dependencies = [ "humantime-serde", "log", "mixnet-contract-common", + "nymcoconut", "nymsphinx", "pin-project", "pretty_env_logger", @@ -3300,7 +3352,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95" dependencies = [ "bitflags", - "cfg-if", + "cfg-if 1.0.0", "foreign-types", "libc", "once_cell", @@ -3404,7 +3456,7 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "instant", "libc", "redox_syscall", @@ -3418,7 +3470,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28141e0cc4143da2443301914478dc976a61ffdb3f043058310c70df2fed8954" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", "redox_syscall", "smallvec 1.8.0", @@ -3567,6 +3619,19 @@ dependencies = [ "indexmap", ] +[[package]] +name = "pickledb" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9161694d67f6c5163519d42be942ae36bbdb55f439460144f105bc4f9f7d1d61" +dependencies = [ + "bincode", + "serde", + "serde_cbor", + "serde_json", + "serde_yaml", +] + [[package]] name = "pin-project" version = "1.0.10" @@ -4720,6 +4785,18 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_yaml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a521f2940385c165a24ee286aa8599633d162077a54bdcae2a6fd5a7bfa7a0" +dependencies = [ + "indexmap", + "ryu", + "serde", + "yaml-rust", +] + [[package]] name = "serial_test" version = "0.5.1" @@ -4761,7 +4838,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" dependencies = [ "block-buffer 0.9.0", - "cfg-if", + "cfg-if 1.0.0", "cpufeatures", "digest 0.9.0", "opaque-debug 0.3.0", @@ -4773,7 +4850,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "cpufeatures", "digest 0.10.3", ] @@ -4800,7 +4877,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ "block-buffer 0.9.0", - "cfg-if", + "cfg-if 1.0.0", "cpufeatures", "digest 0.9.0", "opaque-debug 0.3.0", @@ -5249,7 +5326,7 @@ version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "fastrand", "libc", "redox_syscall", @@ -5727,7 +5804,7 @@ version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a1bdf54a7c28a2bbf701e1d2233f6c77f473486b94bee4f9678da5a148dca7f" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "log", "pin-project-lite", "tracing-attributes", @@ -6037,7 +6114,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6cf88d94e969e7956d924ba70741316796177fa0c79a2c9f4ab04998d96e966e" dependencies = [ "anyhow", - "cfg-if", + "cfg-if 1.0.0", "chrono", "enum-iterator", "getset", @@ -6132,7 +6209,7 @@ version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "serde", "serde_json", "wasm-bindgen-macro", @@ -6159,7 +6236,7 @@ version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e8d7523cb1f2a4c96c1317ca690031b714a51cc14e05f712446691f413f5d39" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "js-sys", "wasm-bindgen", "web-sys", @@ -6412,6 +6489,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "yansi" version = "0.5.0" diff --git a/Cargo.toml b/Cargo.toml index f7d3a9de93..aae00201af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ panic = "abort" resolver = "2" members = [ "clients/client-core", + "clients/credential", "clients/native", "clients/native/websocket-requests", "clients/socks5", @@ -26,6 +27,7 @@ members = [ "common/credentials", "common/crypto", "common/bandwidth-claim-contract", + "common/cosmwasm-smart-contracts/coconut-bandwidth-contract", "common/cosmwasm-smart-contracts/contracts-common", "common/cosmwasm-smart-contracts/mixnet-contract", "common/cosmwasm-smart-contracts/vesting-contract", diff --git a/clients/client-core/Cargo.toml b/clients/client-core/Cargo.toml index 464bf9d0a4..f566d30557 100644 --- a/clients/client-core/Cargo.toml +++ b/clients/client-core/Cargo.toml @@ -32,4 +32,4 @@ validator-client = { path = "../../common/client-libs/validator-client" } tempfile = "3.1.0" [features] -coconut = [] \ No newline at end of file +coconut = ["gateway-client/coconut", "gateway-requests/coconut"] \ No newline at end of file diff --git a/clients/credential/Cargo.lock b/clients/credential/Cargo.lock new file mode 100644 index 0000000000..9b5abe7f4f --- /dev/null +++ b/clients/credential/Cargo.lock @@ -0,0 +1,3453 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aes" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +dependencies = [ + "cfg-if", + "cipher 0.3.0", + "cpufeatures", + "ctr 0.8.0", + "opaque-debug 0.3.0", +] + +[[package]] +name = "aes" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfe0133578c0986e1fe3dfcd4af1cc5b2dd6c3dbf534d69916ce16a2701d40ba" +dependencies = [ + "cfg-if", + "cipher 0.4.3", + "cpufeatures", +] + +[[package]] +name = "anyhow" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" + +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + +[[package]] +name = "async-trait" +version = "0.1.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78" +dependencies = [ + "autocfg 1.1.0", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "az" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f771a5d1f5503f7f4279a30f3643d3421ba149848b89ecaaec0ea2acf04a5ac4" + +[[package]] +name = "base16ct" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "base64ct" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71acf5509fc522cce1b100ac0121c635129bfd4d91cdf036bcc9b9935f97ccf5" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bip32" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "873faa4363bfc54c36a48321da034c92a0645a363eed34d948683ffc1706e37f" +dependencies = [ + "bs58", + "hmac 0.11.0", + "k256 0.10.4", + "once_cell", + "pbkdf2", + "rand_core 0.6.3", + "ripemd160", + "sha2", + "subtle 2.4.1", + "zeroize", +] + +[[package]] +name = "bip39" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e89470017230c38e52b82b3ee3f530db1856ba1d434e3a67a3456a8a8dec5f" +dependencies = [ + "bitcoin_hashes", + "rand 0.6.5", + "rand_core 0.4.2", + "serde", + "unicode-normalization", +] + +[[package]] +name = "bitcoin_hashes" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ce18265ec2324ad075345d5814fbeed4f41f0a660055dc78840b74d19b874b1" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "blake2" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94cb07b0da6a73955f8fb85d24c466778e70cda767a568229b104f0264089330" +dependencies = [ + "byte-tools", + "crypto-mac 0.7.0", + "digest 0.8.1", + "opaque-debug 0.2.3", +] + +[[package]] +name = "blake3" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a08e53fc5a564bb15bfe6fae56bd71522205f1f91893f9c0116edad6496c183f" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "digest 0.10.3", +] + +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +dependencies = [ + "block-padding 0.1.5", + "byte-tools", + "byteorder", + "generic-array 0.12.4", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "block-padding 0.2.1", + "generic-array 0.14.5", +] + +[[package]] +name = "block-buffer" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +dependencies = [ + "generic-array 0.14.5", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +dependencies = [ + "byte-tools", +] + +[[package]] +name = "block-padding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" + +[[package]] +name = "bls12_381" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54757888b09a69be70b5ec303e382a74227392086ba808cb01eeca29233a2397" +dependencies = [ + "digest 0.9.0", + "ff 0.10.1", + "group 0.10.0", + "pairing", + "rand_core 0.6.3", + "subtle 2.4.1", +] + +[[package]] +name = "bs58" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" +dependencies = [ + "sha2", +] + +[[package]] +name = "bumpalo" +version = "3.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" + +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" + +[[package]] +name = "bytemuck" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e851ca7c24871e7336801608a4797d7376545b6928a10d32d75685687141ead" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chacha" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddf3c081b5fba1e5615640aae998e0fbd10c24cbd897ee39ed754a77601a4862" +dependencies = [ + "byteorder", + "keystream", +] + +[[package]] +name = "cipher" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +dependencies = [ + "generic-array 0.14.5", +] + +[[package]] +name = "cipher" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1873270f8f7942c191139cb8a40fd228da6c3fd2fc376d7e92d47aa14aeb59e" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "clap" +version = "3.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8c93436c21e4698bacadf42917db28b23017027a4deccb35dbe47a7e7840123" +dependencies = [ + "atty", + "bitflags", + "clap_derive", + "indexmap", + "lazy_static", + "os_str_bytes", + "strsim", + "termcolor", + "textwrap", +] + +[[package]] +name = "clap_derive" +version = "3.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da95d038ede1a964ce99f49cbe27a7fb538d1da595e4b4f70b8c8f338d17bf16" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags", +] + +[[package]] +name = "coconut-bandwidth-contract-common" +version = "0.1.0" +dependencies = [ + "schemars", + "serde", +] + +[[package]] +name = "coconut-interface" +version = "0.1.0" +dependencies = [ + "getset", + "nymcoconut", + "serde", + "thiserror", +] + +[[package]] +name = "config" +version = "0.1.0" +dependencies = [ + "handlebars", + "humantime-serde", + "network-defaults", + "serde", + "toml", + "url", +] + +[[package]] +name = "const-oid" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d6f2aa4d0537bcc1c74df8755072bd31c1ef1a3a1b85a68e8404a8c353b7b8b" + +[[package]] +name = "const-oid" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "contracts-common" +version = "0.1.0" +dependencies = [ + "cosmwasm-std", +] + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "cosmos-sdk-proto" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0254ffee603f5301d6a66963d9e1cc5091479c22e2e925e1f7689c8027a0828" +dependencies = [ + "prost", + "prost-types", + "tendermint-proto", +] + +[[package]] +name = "cosmrs" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "505ea048e9ff2f906d6b954f9f8157d903ca468bfb301d906b40ecc25ba6838d" +dependencies = [ + "bip32", + "cosmos-sdk-proto", + "ecdsa 0.13.4", + "eyre", + "getrandom 0.2.5", + "k256 0.10.4", + "prost", + "prost-types", + "rand_core 0.6.3", + "serde", + "serde_json", + "subtle-encoding", + "tendermint", + "tendermint-rpc", + "thiserror", +] + +[[package]] +name = "cosmwasm-crypto" +version = "1.0.0-beta7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88c2565b1e73a816fb659ef4838fc356143fbd35f43c48a51d2d7d4e5d6679d3" +dependencies = [ + "digest 0.9.0", + "ed25519-zebra", + "k256 0.9.6", + "rand_core 0.6.3", + "thiserror", +] + +[[package]] +name = "cosmwasm-derive" +version = "1.0.0-beta7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa89fcdf8dbbe0088e663d0a814aa7368e7ebe8fb045a3a150fb5fdc2ffe3b45" +dependencies = [ + "syn", +] + +[[package]] +name = "cosmwasm-std" +version = "1.0.0-beta7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcb8f99a61d0b9069e1afc80a4ffea87dcc3523edd992080923870b13a677da0" +dependencies = [ + "base64", + "cosmwasm-crypto", + "cosmwasm-derive", + "forward_ref", + "schemars", + "serde", + "serde-json-wasm", + "thiserror", + "uint", +] + +[[package]] +name = "cpufeatures" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "credential" +version = "0.1.0" +dependencies = [ + "async-trait", + "bip39", + "clap", + "coconut-bandwidth-contract-common", + "coconut-interface", + "credentials", + "crypto", + "network-defaults", + "pemstore", + "pickledb", + "rand 0.7.3", + "serde", + "thiserror", + "tokio", + "url", + "validator-client", +] + +[[package]] +name = "credentials" +version = "0.1.0" +dependencies = [ + "bls12_381", + "coconut-interface", + "crypto", + "network-defaults", + "thiserror", + "url", + "validator-client", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto" +version = "0.1.0" +dependencies = [ + "aes 0.8.1", + "blake3", + "bs58", + "cipher 0.4.3", + "config", + "ctr 0.9.1", + "digest 0.10.3", + "ed25519-dalek", + "generic-array 0.14.5", + "hkdf 0.12.3", + "hmac 0.12.1", + "nymsphinx-types", + "pemstore", + "rand 0.7.3", + "subtle-encoding", + "x25519-dalek", +] + +[[package]] +name = "crypto-bigint" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83bd3bb4314701c568e340cd8cf78c975aa0ca79e03d3f6d1677d5b0c9c0c03" +dependencies = [ + "generic-array 0.14.5", + "rand_core 0.6.3", + "subtle 2.4.1", + "zeroize", +] + +[[package]] +name = "crypto-bigint" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" +dependencies = [ + "generic-array 0.14.5", + "rand_core 0.6.3", + "subtle 2.4.1", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" +dependencies = [ + "generic-array 0.14.5", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" +dependencies = [ + "generic-array 0.12.4", + "subtle 1.0.0", +] + +[[package]] +name = "crypto-mac" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +dependencies = [ + "generic-array 0.14.5", + "subtle 2.4.1", +] + +[[package]] +name = "ct-logs" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1a816186fa68d9e426e3cb4ae4dff1fcd8e4a2c34b781bf7a822574a0d0aac8" +dependencies = [ + "sct", +] + +[[package]] +name = "ctr" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" +dependencies = [ + "cipher 0.3.0", +] + +[[package]] +name = "ctr" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d14f329cfbaf5d0e06b5e87fff7e265d2673c5ea7d2c27691a2c107db1442a0" +dependencies = [ + "cipher 0.4.3", +] + +[[package]] +name = "curve25519-dalek" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle 2.4.1", + "zeroize", +] + +[[package]] +name = "cw-storage-plus" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d7ee1963302b0ac2a9d42fe0faec826209c17452bfd36fbfd9d002a88929261" +dependencies = [ + "cosmwasm-std", + "schemars", + "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 = "der" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79b71cca7d95d7681a4b3b9cdf63c8dbc3730d0584c2c74e31416d64a90493f4" +dependencies = [ + "const-oid 0.6.2", +] + +[[package]] +name = "der" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" +dependencies = [ + "const-oid 0.7.1", +] + +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array 0.12.4", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array 0.14.5", +] + +[[package]] +name = "digest" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +dependencies = [ + "block-buffer 0.10.2", + "crypto-common", + "subtle 2.4.1", +] + +[[package]] +name = "dyn-clone" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21e50f3adc76d6a43f5ed73b698a87d0760ca74617f60f7c3b879003536fdd28" + +[[package]] +name = "ecdsa" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43ee23aa5b4f68c7a092b5c3beb25f50c406adc75e2363634f242f28ab255372" +dependencies = [ + "der 0.4.5", + "elliptic-curve 0.10.6", + "hmac 0.11.0", + "signature", +] + +[[package]] +name = "ecdsa" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0d69ae62e0ce582d56380743515fefaf1a8c70cec685d9677636d7e30ae9dc9" +dependencies = [ + "der 0.5.1", + "elliptic-curve 0.11.12", + "rfc6979", + "signature", +] + +[[package]] +name = "ed25519" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d5c4b5e5959dc2c2b89918d8e2cc40fcdd623cef026ed09d2f0ee05199dc8e4" +dependencies = [ + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +dependencies = [ + "curve25519-dalek", + "ed25519", + "rand 0.7.3", + "serde", + "sha2", + "zeroize", +] + +[[package]] +name = "ed25519-zebra" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "403ef3e961ab98f0ba902771d29f842058578bb1ce7e3c59dad5a6a93e784c69" +dependencies = [ + "curve25519-dalek", + "hex", + "rand_core 0.6.3", + "serde", + "sha2", + "thiserror", + "zeroize", +] + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "elliptic-curve" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "beca177dcb8eb540133e7680baff45e7cc4d93bf22002676cec549f82343721b" +dependencies = [ + "crypto-bigint 0.2.11", + "ff 0.10.1", + "generic-array 0.14.5", + "group 0.10.0", + "pkcs8 0.7.6", + "rand_core 0.6.3", + "subtle 2.4.1", + "zeroize", +] + +[[package]] +name = "elliptic-curve" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25b477563c2bfed38a3b7a60964c49e058b2510ad3f12ba3483fd8f62c2306d6" +dependencies = [ + "base16ct", + "crypto-bigint 0.3.2", + "der 0.5.1", + "ff 0.11.0", + "generic-array 0.14.5", + "group 0.11.0", + "rand_core 0.6.3", + "sec1", + "subtle 2.4.1", + "zeroize", +] + +[[package]] +name = "encoding_rs" +version = "0.8.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "eyre" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9289ed2c0440a6536e65119725cf91fc2c6b5e513bfd2e36e1134d7cca6ca12f" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" + +[[package]] +name = "fastrand" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +dependencies = [ + "instant", +] + +[[package]] +name = "ff" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0f40b2dcd8bc322217a5f6559ae5f9e9d1de202a2ecee2e9eafcbece7562a4f" +dependencies = [ + "rand_core 0.6.3", + "subtle 2.4.1", +] + +[[package]] +name = "ff" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2958d04124b9f27f175eaeb9a9f383d026098aa837eadd8ba22c11f13a05b9e" +dependencies = [ + "rand_core 0.6.3", + "subtle 2.4.1", +] + +[[package]] +name = "fixed" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86d3f4dd10ddfcb0bd2b2efe9f18aff37ed48265fda3e20e5d53f046aba9d50a" +dependencies = [ + "az", + "bytemuck", + "half", + "serde", + "typenum", +] + +[[package]] +name = "flate2" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" +dependencies = [ + "cfg-if", + "crc32fast", + "libc", + "miniz_oxide", +] + +[[package]] +name = "flex-error" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c606d892c9de11507fa0dcffc116434f94e105d0bbdc4e405b61519464c49d7b" +dependencies = [ + "eyre", + "paste", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + +[[package]] +name = "forward_ref" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8cbd1169bd7b4a0a20d92b9af7a7e0422888bd38a6f5ec29c1fd8c1558a272e" + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "futures" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" + +[[package]] +name = "futures-executor" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" + +[[package]] +name = "futures-macro" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" + +[[package]] +name = "futures-task" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" + +[[package]] +name = "futures-util" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" +dependencies = [ + "typenum", +] + +[[package]] +name = "generic-array" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.10.2+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getset" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e45727250e75cc04ff2846a66397da8ef2b3db8e40e0cef4df67950a07621eb9" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[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.3", + "subtle 2.4.1", +] + +[[package]] +name = "group" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89" +dependencies = [ + "ff 0.11.0", + "rand_core 0.6.3", + "subtle 2.4.1", +] + +[[package]] +name = "h2" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62eeb471aa3e3c9197aa4bfeabfe02982f6dc96f750486c0bb0009ac58b26d2b" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + +[[package]] +name = "handlebars" +version = "3.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4498fc115fa7d34de968184e473529abb40eeb6be8bc5f7faba3d08c316cb3e3" +dependencies = [ + "log", + "pest", + "pest_derive", + "quick-error", + "serde", + "serde_json", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" + +[[package]] +name = "headers" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cff78e5788be1e0ab65b04d306b2ed5092c815ec97ec70f4ebd5aee158aa55d" +dependencies = [ + "base64", + "bitflags", + "bytes", + "headers-core", + "http", + "httpdate", + "mime", + "sha-1 0.10.0", +] + +[[package]] +name = "headers-core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +dependencies = [ + "http", +] + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hex-literal" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" + +[[package]] +name = "hkdf" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01706d578d5c281058480e673ae4086a9f4710d8df1ad80a5b03e39ece5f886b" +dependencies = [ + "digest 0.9.0", + "hmac 0.11.0", +] + +[[package]] +name = "hkdf" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +dependencies = [ + "hmac 0.12.1", +] + +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac 0.11.1", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.3", +] + +[[package]] +name = "http" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9100414882e15fb7feccb4897e5f0ff0ff1ca7d1a86a23208ada4d7a18e6c6c4" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "humantime-serde" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57a3db5ea5923d99402c94e9feb261dc5ee9b4efa158b0315f788cf549cc200c" +dependencies = [ + "humantime", + "serde", +] + +[[package]] +name = "hyper" +version = "0.14.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b26ae0a80afebe130861d90abf98e3814a4f28a4c6ffeb5ab8ebb2be311e0ef2" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-proxy" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca815a891b24fdfb243fa3239c86154392b0953ee584aa1a2a1f66d20cbe75cc" +dependencies = [ + "bytes", + "futures", + "headers", + "http", + "hyper", + "hyper-tls", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-rustls" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f9f7a97316d44c0af9b0301e65010573a853a9fc97046d7331d7f6bc0fd5a64" +dependencies = [ + "ct-logs", + "futures-util", + "hyper", + "log", + "rustls", + "rustls-native-certs", + "tokio", + "tokio-rustls", + "webpki", + "webpki-roots", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "idna" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de910d521f7cc3135c4de8db1cb910e0b5ed1dc6f57c381cd07e8e661ce10094" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + +[[package]] +name = "indexmap" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" +dependencies = [ + "autocfg 1.1.0", + "hashbrown", +] + +[[package]] +name = "inout" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1f03d4ab4d5dc9ec2d219f86c15d2a15fc08239d1cd3b2d6a19717c0a2f443" +dependencies = [ + "generic-array 0.14.5", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "ipnet" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35e70ee094dc02fd9c13fdad4940090f22dbd6ac7c9e7094a46cf0232a50bc7c" + +[[package]] +name = "itertools" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" + +[[package]] +name = "js-sys" +version = "0.3.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "k256" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "903ae2481bcdfdb7b68e0a9baa4b7c9aff600b9ae2e8e5bb5833b8c91ab851ea" +dependencies = [ + "cfg-if", + "ecdsa 0.12.4", + "elliptic-curve 0.10.6", + "sha2", +] + +[[package]] +name = "k256" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19c3a5e0a0b8450278feda242592512e09f61c72e018b8cd5c859482802daf2d" +dependencies = [ + "cfg-if", + "ecdsa 0.13.4", + "elliptic-curve 0.11.12", + "sec1", + "sha2", + "sha3", +] + +[[package]] +name = "keccak" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" + +[[package]] +name = "keystream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33070833c9ee02266356de0c43f723152bd38bd96ddf52c82b3af10c9138b28" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.121" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f" + +[[package]] +name = "libm" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33a33a362ce288760ec6a508b94caaec573ae7d3bbbd91b87aa0bad4456839db" + +[[package]] +name = "linked-hash-map" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" + +[[package]] +name = "lioness" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae926706ba42c425c9457121178330d75e273df2e82e28b758faf3de3a9acb9" +dependencies = [ + "arrayref", + "blake2", + "chacha", + "keystream", +] + +[[package]] +name = "log" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "maybe-uninit" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "miniz_oxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +dependencies = [ + "adler", + "autocfg 1.1.0", +] + +[[package]] +name = "mio" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9" +dependencies = [ + "libc", + "log", + "miow", + "ntapi", + "wasi 0.11.0+wasi-snapshot-preview1", + "winapi", +] + +[[package]] +name = "miow" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +dependencies = [ + "winapi", +] + +[[package]] +name = "mixnet-contract-common" +version = "0.1.0" +dependencies = [ + "az", + "contracts-common", + "cosmwasm-std", + "fixed", + "log", + "network-defaults", + "schemars", + "serde", + "serde_repr", + "thiserror", + "time", +] + +[[package]] +name = "native-tls" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "network-defaults" +version = "0.1.0" +dependencies = [ + "cfg-if", + "hex-literal", + "once_cell", + "serde", + "thiserror", + "url", +] + +[[package]] +name = "ntapi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" +dependencies = [ + "winapi", +] + +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg 1.1.0", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_threads" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aba1801fb138d8e85e11d0fc70baf4fe1cdfffda7c6cd34a854905df588e5ed0" +dependencies = [ + "libc", +] + +[[package]] +name = "nymcoconut" +version = "0.5.0" +dependencies = [ + "bls12_381", + "bs58", + "digest 0.9.0", + "ff 0.10.1", + "getrandom 0.2.5", + "group 0.10.0", + "itertools", + "rand 0.8.5", + "serde", + "serde_derive", + "sha2", + "thiserror", +] + +[[package]] +name = "nymsphinx-types" +version = "0.1.0" +dependencies = [ + "sphinx", +] + +[[package]] +name = "once_cell" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" + +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "openssl" +version = "0.10.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-sys", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb" +dependencies = [ + "autocfg 1.1.0", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "os_str_bytes" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" +dependencies = [ + "memchr", +] + +[[package]] +name = "pairing" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7de9d09263c9966e8196fe0380c9dbbc7ea114b5cf371ba29004bc1f9c6db7f3" +dependencies = [ + "group 0.10.0", +] + +[[package]] +name = "paste" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0744126afe1a6dd7f394cb50a716dbe086cb06e255e53d8d0185d82828358fb5" + +[[package]] +name = "pbkdf2" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05894bce6a1ba4be299d0c5f29563e08af2bc18bb7d48313113bed71e904739" +dependencies = [ + "crypto-mac 0.11.1", +] + +[[package]] +name = "peg" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07c0b841ea54f523f7aa556956fbd293bcbe06f2e67d2eb732b7278aaf1d166a" +dependencies = [ + "peg-macros", + "peg-runtime", +] + +[[package]] +name = "peg-macros" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5aa52829b8decbef693af90202711348ab001456803ba2a98eb4ec8fb70844c" +dependencies = [ + "peg-runtime", + "proc-macro2", + "quote", +] + +[[package]] +name = "peg-runtime" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c719dcf55f09a3a7e764c6649ab594c18a177e3599c467983cdf644bfc0a4088" + +[[package]] +name = "pem" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd56cbd21fea48d0c440b41cd69c589faacade08c992d9a54e471b79d0fd13eb" +dependencies = [ + "base64", + "once_cell", + "regex", +] + +[[package]] +name = "pemstore" +version = "0.1.0" +dependencies = [ + "pem", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pest" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +dependencies = [ + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" +dependencies = [ + "maplit", + "pest", + "sha-1 0.8.2", +] + +[[package]] +name = "pickledb" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9161694d67f6c5163519d42be942ae36bbdb55f439460144f105bc4f9f7d1d61" +dependencies = [ + "bincode", + "serde", + "serde_cbor", + "serde_json", + "serde_yaml", +] + +[[package]] +name = "pin-project" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee3ef9b64d26bad0536099c816c6734379e45bbd5f14798def6809e5cc350447" +dependencies = [ + "der 0.4.5", + "spki 0.4.1", +] + +[[package]] +name = "pkcs8" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cabda3fb821068a9a4fab19a683eac3af12edf0f34b94a8be53c4972b8149d0" +dependencies = [ + "der 0.5.1", + "spki 0.5.4", + "zeroize", +] + +[[package]] +name = "pkg-config" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "prost" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "prost-types" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534b7a0e836e3c482d2693070f982e39e7611da9695d4d1f5a4b186b51faef0a" +dependencies = [ + "bytes", + "prost", +] + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + +[[package]] +name = "quote" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4af2ec4714533fcdf07e886f17025ace8b997b9ce51204ee69b6da831c3da57" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +dependencies = [ + "autocfg 0.1.8", + "libc", + "rand_chacha 0.1.1", + "rand_core 0.4.2", + "rand_hc 0.1.0", + "rand_isaac", + "rand_jitter", + "rand_os", + "rand_pcg", + "rand_xorshift", + "winapi", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc 0.2.0", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.3", +] + +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +dependencies = [ + "autocfg 0.1.8", + "rand_core 0.3.1", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.3", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom 0.2.5", +] + +[[package]] +name = "rand_distr" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e9532ada3929fb8b2e9dbe28d1e06c9b2cc65813f074fcb6bd5fbefeff9d56" +dependencies = [ + "num-traits", + "rand 0.7.3", +] + +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_jitter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" +dependencies = [ + "libc", + "rand_core 0.4.2", + "winapi", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +dependencies = [ + "cloudabi", + "fuchsia-cprng", + "libc", + "rand_core 0.4.2", + "rdrand", + "winapi", +] + +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +dependencies = [ + "autocfg 0.1.8", + "rand_core 0.4.2", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "redox_syscall" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae183fc1b06c149f0c1793e1eb447c8b04bfe46d48e9e48bfb8d2d7ed64ecf0" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "reqwest" +version = "0.11.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46a1f7aa4f35e5e8b4160449f51afc758f0ce6454315a9fa7d0d113e958c41eb" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "lazy_static", + "log", + "mime", + "native-tls", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-native-tls", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "rfc6979" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" +dependencies = [ + "crypto-bigint 0.3.2", + "hmac 0.11.0", + "zeroize", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + +[[package]] +name = "ripemd160" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eca4ecc81b7f313189bf73ce724400a07da2a6dac19588b03c8bd76a2dcc251" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + +[[package]] +name = "rustls" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" +dependencies = [ + "base64", + "log", + "ring", + "sct", + "webpki", +] + +[[package]] +name = "rustls-native-certs" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a07b7c1885bd8ed3831c289b7870b13ef46fe0e856d288c30d9cc17d75a2092" +dependencies = [ + "openssl-probe", + "rustls", + "schannel", + "security-framework", +] + +[[package]] +name = "ryu" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" +dependencies = [ + "lazy_static", + "winapi", +] + +[[package]] +name = "schemars" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6b5a3c80cea1ab61f4260238409510e814e38b4b563c06044edf91e7dc070e3" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41ae4dce13e8614c46ac3c38ef1c0d668b101df6ac39817aebdaa26642ddae9b" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn", +] + +[[package]] +name = "sct" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "sec1" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1" +dependencies = [ + "der 0.5.1", + "generic-array 0.14.5", + "pkcs8 0.8.0", + "subtle 2.4.1", + "zeroize", +] + +[[package]] +name = "security-framework" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.136" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-json-wasm" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "042ac496d97e5885149d34139bad1d617192770d7eb8f1866da2317ff4501853" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_bytes" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16ae07dd2f88a366f15bd0632ba725227018c69a1c8550a927324f8eb8368bb9" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_cbor" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +dependencies = [ + "half", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.136" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_derive_internals" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dbab34ca63057a1f15280bdf3c39f2b1eb1b54c17e98360e511637aef7418c6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98d0516900518c29efa217c298fa1f4e6c6ffc85ae29fd7f4ee48f176e1a9ed5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a521f2940385c165a24ee286aa8599633d162077a54bdcae2a6fd5a7bfa7a0" +dependencies = [ + "indexmap", + "ryu", + "serde", + "yaml-rust", +] + +[[package]] +name = "sha-1" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" +dependencies = [ + "block-buffer 0.7.3", + "digest 0.8.1", + "fake-simd", + "opaque-debug 0.2.3", +] + +[[package]] +name = "sha-1" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.3", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + +[[package]] +name = "sha3" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "keccak", + "opaque-debug 0.3.0", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2807892cfa58e081aa1f1111391c7a0649d4fa127a4ffbe34bcbfb35a1171a4" +dependencies = [ + "digest 0.9.0", + "rand_core 0.6.3", +] + +[[package]] +name = "slab" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" + +[[package]] +name = "smallvec" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97fcaeba89edba30f044a10c6a3cc39df9c3f17d7cd829dd1446cab35f890e0" +dependencies = [ + "maybe-uninit", +] + +[[package]] +name = "socket2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "sphinx" +version = "0.1.0" +source = "git+https://github.com/nymtech/sphinx?rev=c494250f2a78bed33a618d470792418eee932859#c494250f2a78bed33a618d470792418eee932859" +dependencies = [ + "aes 0.7.5", + "arrayref", + "blake2", + "bs58", + "byteorder", + "chacha", + "curve25519-dalek", + "digest 0.9.0", + "hkdf 0.11.0", + "hmac 0.11.0", + "lioness", + "log", + "rand 0.7.3", + "rand_distr", + "sha2", + "subtle 2.4.1", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spki" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c01a0c15da1b0b0e1494112e7af814a678fec9bd157881b49beac661e9b6f32" +dependencies = [ + "der 0.4.5", +] + +[[package]] +name = "spki" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d01ac02a6ccf3e07db148d2be087da624fea0221a16152ed01f0496a6b0a27" +dependencies = [ + "base64ct", + "der 0.5.1", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "subtle" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "subtle-encoding" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dcb1ed7b8330c5eed5441052651dd7a12c75e2ed88f2ec024ae1fa3a5e59945" +dependencies = [ + "zeroize", +] + +[[package]] +name = "syn" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea297be220d52398dcc07ce15a209fce436d361735ac1db700cab3b6cdfb9f54" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "tendermint" +version = "0.23.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9ef686b8ecd36550d0581f0989c9d8607090b23005df479d8e6ba348b5800b9" +dependencies = [ + "async-trait", + "bytes", + "ed25519", + "ed25519-dalek", + "flex-error", + "futures", + "k256 0.10.4", + "num-traits", + "once_cell", + "prost", + "prost-types", + "ripemd160", + "serde", + "serde_bytes", + "serde_json", + "serde_repr", + "sha2", + "signature", + "subtle 2.4.1", + "subtle-encoding", + "tendermint-proto", + "time", + "zeroize", +] + +[[package]] +name = "tendermint-config" +version = "0.23.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc127f82e7a8c7337c1f293d65a821380d3407c4c44bc979ef4da0ebc3b31ed" +dependencies = [ + "flex-error", + "serde", + "serde_json", + "tendermint", + "toml", + "url", +] + +[[package]] +name = "tendermint-proto" +version = "0.23.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e0a0251fd81bed7420bea0f4d91c2a58f6c9fa34d5b2f70bed0ba8890de5aa" +dependencies = [ + "bytes", + "flex-error", + "num-derive", + "num-traits", + "prost", + "prost-types", + "serde", + "serde_bytes", + "subtle-encoding", + "time", +] + +[[package]] +name = "tendermint-rpc" +version = "0.23.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626c493e9ced3a9de37583bbd929f4b6dbd49aa513ab9b4776aa44a9332ce9b5" +dependencies = [ + "async-trait", + "bytes", + "flex-error", + "futures", + "getrandom 0.2.5", + "http", + "hyper", + "hyper-proxy", + "hyper-rustls", + "peg", + "pin-project", + "serde", + "serde_bytes", + "serde_json", + "subtle-encoding", + "tendermint", + "tendermint-config", + "tendermint-proto", + "thiserror", + "time", + "tokio", + "tracing", + "url", + "uuid", + "walkdir", +] + +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" + +[[package]] +name = "thiserror" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd" +dependencies = [ + "itoa", + "libc", + "num_threads", + "time-macros", +] + +[[package]] +name = "time-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" + +[[package]] +name = "tokio" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee" +dependencies = [ + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "once_cell", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" +dependencies = [ + "rustls", + "tokio", + "webpki", +] + +[[package]] +name = "tokio-util" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +dependencies = [ + "serde", +] + +[[package]] +name = "tower-service" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" + +[[package]] +name = "tracing" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a1bdf54a7c28a2bbf701e1d2233f6c77f473486b94bee4f9678da5a148dca7f" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa31669fa42c09c34d94d8165dd2012e8ff3c66aca50f3bb226b68f216f2706c" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "ucd-trie" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" + +[[package]] +name = "uint" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6470ab50f482bde894a037a57064480a246dbfdd5960bd65a44824693f08da5f" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" + +[[package]] +name = "unicode-normalization" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09c8070a9942f5e7cfccd93f490fdebd230ee3c3c9f107cb25bad5351ef671cf" +dependencies = [ + "smallvec", +] + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "url" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", + "serde", +] + +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" + +[[package]] +name = "validator-api-requests" +version = "0.1.0" +dependencies = [ + "serde", +] + +[[package]] +name = "validator-client" +version = "0.1.0" +dependencies = [ + "async-trait", + "base64", + "bip39", + "coconut-interface", + "config", + "cosmrs", + "cosmwasm-std", + "flate2", + "itertools", + "log", + "mixnet-contract-common", + "network-defaults", + "prost", + "reqwest", + "serde", + "serde_json", + "sha2", + "thiserror", + "url", + "validator-api-requests", + "vesting-contract", + "vesting-contract-common", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "vesting-contract" +version = "0.1.0" +dependencies = [ + "config", + "cosmwasm-std", + "cw-storage-plus 0.12.1", + "mixnet-contract-common", + "schemars", + "serde", + "thiserror", + "vesting-contract-common", +] + +[[package]] +name = "vesting-contract-common" +version = "0.1.0" +dependencies = [ + "config", + "cosmwasm-std", + "cw-storage-plus 0.11.1", + "mixnet-contract-common", + "schemars", + "serde", +] + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eb6ec270a31b1d3c7e266b999739109abce8b6c87e4b31fcfcd788b65267395" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2" + +[[package]] +name = "web-sys" +version = "0.3.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki" +version = "0.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" +dependencies = [ + "webpki", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] + +[[package]] +name = "x25519-dalek" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2392b6b94a576b4e2bf3c5b2757d63f10ada8020a2e4d08ac849ebcf6ea8e077" +dependencies = [ + "curve25519-dalek", + "rand_core 0.5.1", + "zeroize", +] + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "zeroize" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] diff --git a/clients/credential/Cargo.toml b/clients/credential/Cargo.toml new file mode 100644 index 0000000000..b0a4bc8b68 --- /dev/null +++ b/clients/credential/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "credential" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +async-trait = "0.1.52" +bip39 = "1.0.1" +cfg-if = "0.1" +clap = { version = "3.0.10", features = ["cargo", "derive"] } +pickledb = "0.4.1" +rand = "0.7.3" +serde = { version = "1.0", features = ["derive"] } +thiserror = "1.0" +url = "2.2" +tokio = { version = "1.4", features = ["rt-multi-thread", "net", "signal", "macros"] } # async runtime + +coconut-bandwidth-contract-common = { path = "../../common/cosmwasm-smart-contracts/coconut-bandwidth-contract" } +coconut-interface = { path = "../../common/coconut-interface" } +credentials = { path = "../../common/credentials" } +crypto = { path = "../../common/crypto", features = ["rand", "asymmetric", "symmetric", "aes", "hashing"] } +network-defaults = { path = "../../common/network-defaults" } +pemstore = { path = "../../common/pemstore" } +validator-client = { path = "../../common/client-libs/validator-client", features = ["nymd-client"] } + +[features] +coconut = ["credentials/coconut"] \ No newline at end of file diff --git a/clients/credential/src/client.rs b/clients/credential/src/client.rs new file mode 100644 index 0000000000..678a4bdd1d --- /dev/null +++ b/clients/credential/src/client.rs @@ -0,0 +1,69 @@ +// Copyright 2022 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use bip39::Mnemonic; +use coconut_bandwidth_contract_common::deposit::DepositData; +use std::str::FromStr; +use url::Url; + +use crate::error::Result; +use crate::{CONTRACT_ADDRESS, MNEMONIC, NYMD_URL}; + +use coconut_bandwidth_contract_common::msg::ExecuteMsg; +use network_defaults::DEFAULT_NETWORK; +use validator_client::nymd::{ + AccountId, CosmosCoin, Decimal, Denom, NymdClient, SigningNymdClient, +}; + +pub(crate) struct Client { + nymd_client: NymdClient, + denom: Denom, + contract_address: AccountId, +} + +impl Client { + pub fn new() -> Self { + let nymd_url = Url::from_str(NYMD_URL).unwrap(); + let mnemonic = Mnemonic::from_str(MNEMONIC).unwrap(); + let nymd_client = NymdClient::connect_with_mnemonic( + DEFAULT_NETWORK, + nymd_url.as_ref(), + None, + None, + None, + mnemonic, + None, + ) + .unwrap(); + let denom = Denom::from_str(network_defaults::DENOM).unwrap(); + let contract_address = AccountId::from_str(CONTRACT_ADDRESS).unwrap(); + + Client { + nymd_client, + denom, + contract_address, + } + } + + pub async fn deposit( + &self, + amount: u64, + info: &str, + verification_key: String, + encryption_key: String, + ) -> Result { + let req = ExecuteMsg::DepositFunds { + data: DepositData::new(info.to_string(), verification_key, encryption_key), + }; + let funds = vec![CosmosCoin { + denom: self.denom.clone(), + amount: Decimal::from(amount), + }]; + Ok(self + .nymd_client + .execute(&self.contract_address, &req, Default::default(), "", funds) + .await? + .transaction_hash + .to_string()) + } +} diff --git a/clients/credential/src/commands.rs b/clients/credential/src/commands.rs new file mode 100644 index 0000000000..f61ff27fd3 --- /dev/null +++ b/clients/credential/src/commands.rs @@ -0,0 +1,186 @@ +// Copyright 2022 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use async_trait::async_trait; +use clap::{Args, Subcommand}; +use pickledb::PickleDb; +use rand::rngs::OsRng; +use std::str::FromStr; +use url::Url; + +use coconut_interface::{Attribute, Base58, BlindSignRequest, Bytable, Parameters}; +use credentials::coconut::bandwidth::{BandwidthVoucher, TOTAL_ATTRIBUTES}; +use credentials::coconut::utils::obtain_aggregate_signature; +use crypto::asymmetric::{encryption, identity}; +use network_defaults::VOUCHER_INFO; +use validator_client::nymd::tx::Hash; + +use crate::client::Client; +use crate::error::{CredentialClientError, Result}; +use crate::state::{KeyPair, RequestData, State}; +use crate::SIGNER_AUTHORITIES; + +#[derive(Subcommand)] +pub(crate) enum Commands { + /// Deposit funds for buying coconut credential + Deposit(Deposit), + /// Lists the tx hashes of previous deposits + ListDeposits(ListDeposits), + /// Get a credential for a given deposit + GetCredential(GetCredential), +} + +#[async_trait] +pub(crate) trait Execute { + async fn execute(&self, db: &mut PickleDb) -> Result<()>; +} + +#[derive(Args, Clone)] +pub(crate) struct Deposit { + /// The amount that needs to be deposited + #[clap(long)] + amount: u64, +} + +#[async_trait] +impl Execute for Deposit { + async fn execute(&self, db: &mut PickleDb) -> Result<()> { + let mut rng = OsRng; + let signing_keypair = KeyPair::from(identity::KeyPair::new(&mut rng)); + let encryption_keypair = KeyPair::from(encryption::KeyPair::new(&mut rng)); + + let client = Client::new(); + let tx_hash = client + .deposit( + self.amount, + VOUCHER_INFO, + signing_keypair.public_key.clone(), + encryption_keypair.public_key.clone(), + ) + .await?; + + let state = State { + amount: self.amount, + tx_hash: tx_hash.clone(), + signing_keypair, + encryption_keypair, + blind_request_data: None, + signature: None, + }; + db.set(&tx_hash, &state).unwrap(); + + println!("{:?}", state); + + Ok(()) + } +} + +#[derive(Args, Clone)] +pub(crate) struct ListDeposits {} + +#[async_trait] +impl Execute for ListDeposits { + async fn execute(&self, db: &mut PickleDb) -> Result<()> { + for kv in db.iter() { + println!("{:?}", kv.get_value::()); + } + + Ok(()) + } +} + +#[derive(Args, Clone)] +pub(crate) struct GetCredential { + /// The hash of a successful deposit transaction + #[clap(long)] + tx_hash: String, + /// If we want to get the signature without attaching a blind sign request; it is expected that + /// there is already a signature stored on the signer + #[clap(long, parse(from_flag))] + __no_request: bool, +} + +#[async_trait] +impl Execute for GetCredential { + async fn execute(&self, db: &mut PickleDb) -> Result<()> { + let mut state = db + .get::(&self.tx_hash) + .ok_or(CredentialClientError::NoDeposit)?; + let urls = SIGNER_AUTHORITIES.map(|addr| Url::from_str(addr).unwrap()); + + let params = Parameters::new(TOTAL_ATTRIBUTES).unwrap(); + let bandwidth_credential_attributes = if self.__no_request { + if let Some(blind_request_data) = state.blind_request_data { + let serial_number = + Attribute::try_from_byte_slice(&blind_request_data.serial_number) + .map_err(|_| CredentialClientError::CorruptedBlindSignRequest)?; + let binding_number = + Attribute::try_from_byte_slice(&blind_request_data.binding_number) + .map_err(|_| CredentialClientError::CorruptedBlindSignRequest)?; + let pedersen_commitments_openings = vec![ + Attribute::try_from_byte_slice(&blind_request_data.first_attribute) + .map_err(|_| CredentialClientError::CorruptedBlindSignRequest)?, + Attribute::try_from_byte_slice(&blind_request_data.second_attribute) + .map_err(|_| CredentialClientError::CorruptedBlindSignRequest)?, + ]; + let blind_sign_request = + BlindSignRequest::from_bytes(blind_request_data.blind_sign_req.as_slice()) + .map_err(|_| CredentialClientError::CorruptedBlindSignRequest)?; + BandwidthVoucher::new_with_blind_sign_req( + [serial_number, binding_number], + [&state.amount.to_string(), VOUCHER_INFO], + Hash::from_str(&self.tx_hash) + .map_err(|_| CredentialClientError::InvalidTxHash)?, + identity::PrivateKey::from_base58_string(&state.signing_keypair.private_key)?, + encryption::PrivateKey::from_base58_string( + &state.encryption_keypair.private_key, + )?, + pedersen_commitments_openings, + blind_sign_request, + ) + } else { + return Err(CredentialClientError::NoLocalBlindSignRequest); + } + } else { + BandwidthVoucher::new( + ¶ms, + state.amount.to_string(), + VOUCHER_INFO.to_string(), + Hash::from_str(&self.tx_hash).map_err(|_| CredentialClientError::InvalidTxHash)?, + identity::PrivateKey::from_base58_string(&state.signing_keypair.private_key)?, + encryption::PrivateKey::from_base58_string(&state.encryption_keypair.private_key)?, + ) + }; + + // Back up the blind sign req data, in case of sporadic failures + state.blind_request_data = Some(RequestData::new( + bandwidth_credential_attributes.get_private_attributes(), + bandwidth_credential_attributes.pedersen_commitments_openings(), + bandwidth_credential_attributes.blind_sign_request(), + )?); + db.set(&self.tx_hash, &state).unwrap(); + + let signature = + obtain_aggregate_signature(¶ms, &bandwidth_credential_attributes, &urls).await?; + state.signature = Some(signature.to_bs58()); + db.set(&self.tx_hash, &state).unwrap(); + + println!("Signature: {:?}", state.signature); + + Ok(()) + } +} + +#[derive(Args, Clone)] +pub(crate) struct SpendCredential { + /// Spend one of the acquired credentials + #[clap(long)] + id: usize, +} + +#[async_trait] +impl Execute for SpendCredential { + async fn execute(&self, _db: &mut PickleDb) -> Result<()> { + Ok(()) + } +} diff --git a/clients/credential/src/error.rs b/clients/credential/src/error.rs new file mode 100644 index 0000000000..c3eb626bde --- /dev/null +++ b/clients/credential/src/error.rs @@ -0,0 +1,41 @@ +// Copyright 2022 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use thiserror::Error; + +use credentials::error::Error as CredentialError; +use crypto::asymmetric::encryption::KeyRecoveryError; +use crypto::asymmetric::identity::Ed25519RecoveryError; +use validator_client::nymd::error::NymdError; + +pub type Result = std::result::Result; + +#[derive(Error, Debug)] +pub enum CredentialClientError { + #[error("Nymd error: {0}")] + Nymd(#[from] NymdError), + + #[error("Credential error: {0}")] + Credential(#[from] CredentialError), + + #[error("No previous deposit with that tx hash")] + NoDeposit, + + #[error("Wrong number of attributes")] + WrongAttributeNumber, + + #[error("Could not find any backed up blind sign request data")] + NoLocalBlindSignRequest, + + #[error("The local blind sign request data is corrupted")] + CorruptedBlindSignRequest, + + #[error("The tx hash provided is not valid")] + InvalidTxHash, + + #[error("Could not parse Ed25519 data")] + Ed25519ParseError(#[from] Ed25519RecoveryError), + + #[error("Could not parse X25519 data")] + X25519ParseError(#[from] KeyRecoveryError), +} diff --git a/clients/credential/src/main.rs b/clients/credential/src/main.rs new file mode 100644 index 0000000000..be5b4c1522 --- /dev/null +++ b/clients/credential/src/main.rs @@ -0,0 +1,61 @@ +// Copyright 2022 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +cfg_if::cfg_if! { + if #[cfg(feature = "coconut")] { + + mod client; + mod commands; + mod error; + mod state; + + use commands::{Commands, Execute}; + use error::Result; + + use clap::Parser; + use pickledb::{PickleDb, PickleDbDumpPolicy, SerializationMethod}; + + pub const MNEMONIC: &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"; + pub const NYMD_URL: &str = "http://127.0.0.1:26657"; + pub const CONTRACT_ADDRESS: &str = "nymt1vhjnzk9ly03dugffvzfcwgry4dgc8x0sscmfl2"; + pub const SIGNER_AUTHORITIES: [&str; 1] = [ + "http://127.0.0.1:8080", + ]; + + #[derive(Parser)] + #[clap(author = "Nymtech", version, about)] + struct Cli { + #[clap(subcommand)] + command: Commands, + } + + #[tokio::main] + async fn main() -> Result<()> { + let args = Cli::parse(); + let mut db = match PickleDb::load( + "credential.db", + PickleDbDumpPolicy::AutoDump, + SerializationMethod::Json, + ) { + Ok(db) => db, + Err(_) => PickleDb::new( + "credential.db", + PickleDbDumpPolicy::AutoDump, + SerializationMethod::Json, + ), + }; + + match &args.command { + Commands::Deposit(m) => m.execute(&mut db).await?, + Commands::ListDeposits(m) => m.execute(&mut db).await?, + Commands::GetCredential(m) => m.execute(&mut db).await?, + } + + Ok(()) + } + } else { + fn main() { + println!("Crate only designed for coconut feature"); + } + } +} diff --git a/clients/credential/src/state.rs b/clients/credential/src/state.rs new file mode 100644 index 0000000000..6da1ae6faa --- /dev/null +++ b/clients/credential/src/state.rs @@ -0,0 +1,72 @@ +// Copyright 2022 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use coconut_interface::{Attribute, BlindSignRequest, Bytable, PrivateAttribute}; +use serde::{Deserialize, Serialize}; + +use crypto::asymmetric::{encryption, identity}; + +use crate::error::{CredentialClientError, Result}; + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub(crate) struct KeyPair { + pub public_key: String, + pub private_key: String, +} + +impl From 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 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(), + } + } +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub(crate) struct State { + pub amount: u64, + pub tx_hash: String, + pub signing_keypair: KeyPair, + pub encryption_keypair: KeyPair, + pub blind_request_data: Option, + pub signature: Option, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub(crate) struct RequestData { + pub serial_number: Vec, + pub binding_number: Vec, + pub first_attribute: Vec, + pub second_attribute: Vec, + pub blind_sign_req: Vec, +} + +impl RequestData { + pub fn new( + private_attributes: Vec, + attributes: &[Attribute], + blind_sign_request: &BlindSignRequest, + ) -> Result { + if private_attributes.len() != 2 || attributes.len() != 2 { + Err(CredentialClientError::WrongAttributeNumber) + } else { + Ok(RequestData { + serial_number: private_attributes[0].to_byte_vec(), + binding_number: private_attributes[1].to_byte_vec(), + first_attribute: attributes[0].to_byte_vec(), + second_attribute: attributes[1].to_byte_vec(), + blind_sign_req: blind_sign_request.to_bytes(), + }) + } + } +} diff --git a/clients/native/Cargo.toml b/clients/native/Cargo.toml index bbb1ba86db..9adeaa4924 100644 --- a/clients/native/Cargo.toml +++ b/clients/native/Cargo.toml @@ -47,7 +47,7 @@ version-checker = { path = "../../common/version-checker" } network-defaults = { path = "../../common/network-defaults" } [features] -coconut = ["coconut-interface", "credentials", "gateway-requests/coconut", "gateway-client/coconut"] +coconut = ["coconut-interface", "credentials", "credentials/coconut", "gateway-requests/coconut", "gateway-client/coconut"] eth = [] [dev-dependencies] diff --git a/clients/native/src/commands/init.rs b/clients/native/src/commands/init.rs index d6cbc09ba4..f0de4a445d 100644 --- a/clients/native/src/commands/init.rs +++ b/clients/native/src/commands/init.rs @@ -5,11 +5,12 @@ use clap::{App, Arg, ArgMatches}; use client_core::client::key_manager::KeyManager; use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder; #[cfg(feature = "coconut")] -use coconut_interface::{hash_to_scalar, Credential, Parameters}; +use coconut_interface::{Credential, Parameters}; use config::NymConfig; #[cfg(feature = "coconut")] -use credentials::coconut::bandwidth::{ - obtain_signature, prepare_for_spending, BandwidthVoucherAttributes, TOTAL_ATTRIBUTES, +use credentials::coconut::{ + bandwidth::prepare_for_spending, bandwidth::BandwidthVoucher, bandwidth::TOTAL_ATTRIBUTES, + utils::obtain_aggregate_signature, }; #[cfg(feature = "coconut")] use credentials::obtain_aggregate_verification_key; @@ -17,7 +18,7 @@ use crypto::asymmetric::{encryption, identity}; use gateway_client::GatewayClient; use gateway_requests::registration::handshake::SharedKeys; #[cfg(feature = "coconut")] -use network_defaults::BANDWIDTH_VALUE; +use network_defaults::{BANDWIDTH_VALUE, VOUCHER_INFO}; use nymsphinx::addressing::clients::Recipient; use nymsphinx::addressing::nodes::NodeIdentity; use rand::rngs::OsRng; @@ -28,6 +29,8 @@ use std::sync::Arc; use std::time::Duration; use topology::{filter::VersionFilterable, gateway}; use url::Url; +#[cfg(feature = "coconut")] +use validator_client::nymd::tx::Hash; use crate::client::config::Config; use crate::commands::override_config; @@ -107,15 +110,25 @@ async fn _prepare_temporary_credential(validators: &[Url], raw_identity: &[u8]) .expect("could not obtain aggregate verification key of validators"); let params = Parameters::new(TOTAL_ATTRIBUTES).unwrap(); - let bandwidth_credential_attributes = BandwidthVoucherAttributes { - serial_number: params.random_scalar(), - binding_number: params.random_scalar(), - voucher_value: hash_to_scalar(BANDWIDTH_VALUE.to_be_bytes()), - voucher_info: hash_to_scalar(String::from("BandwidthVoucher").as_bytes()), - }; + let mut rng = OsRng; + let bandwidth_credential_attributes = BandwidthVoucher::new( + ¶ms, + BANDWIDTH_VALUE.to_string(), + VOUCHER_INFO.to_string(), + Hash::new([0; 32]), + // workaround for putting a valid value here, without deriving clone for the private + // key, until we have actual useful values + identity::PrivateKey::from_base58_string( + identity::KeyPair::new(&mut rng) + .private_key() + .to_base58_string(), + ) + .unwrap(), + encryption::KeyPair::new(&mut rng).private_key().clone(), + ); let bandwidth_credential = - obtain_signature(¶ms, &bandwidth_credential_attributes, validators) + obtain_aggregate_signature(¶ms, &bandwidth_credential_attributes, validators) .await .expect("could not obtain bandwidth credential"); diff --git a/clients/socks5/Cargo.toml b/clients/socks5/Cargo.toml index b5116794ff..6443190796 100644 --- a/clients/socks5/Cargo.toml +++ b/clients/socks5/Cargo.toml @@ -42,7 +42,7 @@ version-checker = { path = "../../common/version-checker" } network-defaults = { path = "../../common/network-defaults" } [features] -coconut = ["coconut-interface", "credentials", "gateway-requests/coconut", "gateway-client/coconut"] +coconut = ["coconut-interface", "credentials", "gateway-requests/coconut", "gateway-client/coconut", "credentials/coconut"] eth = [] [build-dependencies] diff --git a/clients/socks5/src/commands/init.rs b/clients/socks5/src/commands/init.rs index 09254d7583..9751365a4f 100644 --- a/clients/socks5/src/commands/init.rs +++ b/clients/socks5/src/commands/init.rs @@ -5,11 +5,12 @@ use clap::{App, Arg, ArgMatches}; use client_core::client::key_manager::KeyManager; use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder; #[cfg(feature = "coconut")] -use coconut_interface::{hash_to_scalar, Credential, Parameters}; +use coconut_interface::{Credential, Parameters}; use config::NymConfig; #[cfg(feature = "coconut")] -use credentials::coconut::bandwidth::{ - obtain_signature, prepare_for_spending, BandwidthVoucherAttributes, TOTAL_ATTRIBUTES, +use credentials::coconut::{ + bandwidth::prepare_for_spending, bandwidth::BandwidthVoucher, bandwidth::TOTAL_ATTRIBUTES, + utils::obtain_aggregate_signature, }; #[cfg(feature = "coconut")] use credentials::obtain_aggregate_verification_key; @@ -26,6 +27,8 @@ use std::sync::Arc; use std::time::Duration; use topology::{filter::VersionFilterable, gateway}; use url::Url; +#[cfg(feature = "coconut")] +use validator_client::nymd::tx::Hash; use crate::client::config::Config; use crate::commands::override_config; @@ -107,15 +110,25 @@ async fn _prepare_temporary_credential(validators: &[Url], raw_identity: &[u8]) .expect("could not obtain aggregate verification key of validators"); let params = Parameters::new(TOTAL_ATTRIBUTES).unwrap(); - let bandwidth_credential_attributes = BandwidthVoucherAttributes { - serial_number: params.random_scalar(), - binding_number: params.random_scalar(), - voucher_value: hash_to_scalar(BANDWIDTH_VALUE.to_be_bytes()), - voucher_info: hash_to_scalar("BandwidthVoucher"), - }; + let mut rng = OsRng; + let bandwidth_credential_attributes = BandwidthVoucher::new( + ¶ms, + BANDWIDTH_VALUE.to_string(), + network_defaults::VOUCHER_INFO.to_string(), + Hash::new([0; 32]), + // workaround for putting a valid value here, without deriving clone for the private + // key, until we have actual useful values + identity::PrivateKey::from_base58_string( + identity::KeyPair::new(&mut rng) + .private_key() + .to_base58_string(), + ) + .unwrap(), + encryption::KeyPair::new(&mut rng).private_key().clone(), + ); let bandwidth_credential = - obtain_signature(¶ms, &bandwidth_credential_attributes, validators) + obtain_aggregate_signature(¶ms, &bandwidth_credential_attributes, validators) .await .expect("could not obtain bandwidth credential"); diff --git a/common/client-libs/gateway-client/Cargo.toml b/common/client-libs/gateway-client/Cargo.toml index a48944f975..72f5ed8b4c 100644 --- a/common/client-libs/gateway-client/Cargo.toml +++ b/common/client-libs/gateway-client/Cargo.toml @@ -19,6 +19,7 @@ secp256k1 = "0.20.3" web3 = { version = "0.17.0", default-features = false } # internal +cosmrs = { version = "0.4.1", optional = true } credentials = { path = "../../credentials" } crypto = { path = "../../crypto" } gateway-requests = { path = "../../../gateway/gateway-requests" } @@ -26,6 +27,7 @@ nymsphinx = { path = "../../nymsphinx" } pemstore = { path = "../../pemstore" } coconut-interface = { path = "../../coconut-interface", optional = true } network-defaults = { path = "../../network-defaults" } +validator-client = { path = "../validator-client", optional = true } [dependencies.tungstenite] version = "0.13" @@ -67,6 +69,6 @@ features = ["js"] #url = "2.1" [features] -coconut = ["gateway-requests/coconut", "coconut-interface"] +coconut = ["gateway-requests/coconut", "coconut-interface", "validator-client", "credentials/coconut", "cosmrs"] wasm = ["web3/wasm", "web3/http", "web3/signing"] default = ["web3/default"] \ No newline at end of file diff --git a/common/client-libs/gateway-client/src/bandwidth.rs b/common/client-libs/gateway-client/src/bandwidth.rs index baf5db93e6..2743bca707 100644 --- a/common/client-libs/gateway-client/src/bandwidth.rs +++ b/common/client-libs/gateway-client/src/bandwidth.rs @@ -1,18 +1,18 @@ // Copyright 2021 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 +#[cfg(feature = "coconut")] +use cosmrs::tx::Hash; #[cfg(feature = "coconut")] use credentials::coconut::{ - bandwidth::{ - obtain_signature, prepare_for_spending, BandwidthVoucherAttributes, TOTAL_ATTRIBUTES, - }, - utils::obtain_aggregate_verification_key, + bandwidth::{prepare_for_spending, BandwidthVoucher, TOTAL_ATTRIBUTES}, + utils::{obtain_aggregate_signature, obtain_aggregate_verification_key}, }; #[cfg(not(feature = "coconut"))] use credentials::token::bandwidth::TokenCredential; -#[cfg(not(feature = "coconut"))] +#[cfg(feature = "coconut")] +use crypto::asymmetric::encryption; use crypto::asymmetric::identity; -use crypto::asymmetric::identity::PublicKey; use network_defaults::BANDWIDTH_VALUE; #[cfg(not(feature = "coconut"))] use network_defaults::{ @@ -22,7 +22,6 @@ use network_defaults::{ }; #[cfg(not(feature = "coconut"))] use pemstore::traits::PemStorableKeyPair; -#[cfg(not(feature = "coconut"))] use rand::rngs::OsRng; #[cfg(not(feature = "coconut"))] use secp256k1::SecretKey; @@ -73,7 +72,7 @@ pub struct BandwidthController { #[cfg(feature = "coconut")] validator_endpoints: Vec, #[cfg(feature = "coconut")] - identity: PublicKey, + identity: identity::PublicKey, #[cfg(not(feature = "coconut"))] contract: Contract, #[cfg(not(feature = "coconut"))] @@ -86,7 +85,7 @@ pub struct BandwidthController { impl BandwidthController { #[cfg(feature = "coconut")] - pub fn new(validator_endpoints: Vec, identity: PublicKey) -> Self { + pub fn new(validator_endpoints: Vec, identity: identity::PublicKey) -> Self { BandwidthController { validator_endpoints, identity, @@ -175,17 +174,25 @@ impl BandwidthController { let verification_key = obtain_aggregate_verification_key(&self.validator_endpoints).await?; let params = coconut_interface::Parameters::new(TOTAL_ATTRIBUTES).unwrap(); + let mut rng = OsRng; // TODO: Decide what is the value and additional info associated with the bandwidth voucher - let bandwidth_credential_attributes = BandwidthVoucherAttributes { - serial_number: params.random_scalar(), - binding_number: params.random_scalar(), - voucher_value: coconut_interface::hash_to_scalar(BANDWIDTH_VALUE.to_be_bytes()), - voucher_info: coconut_interface::hash_to_scalar( - String::from("BandwidthVoucher").as_bytes(), - ), - }; + let bandwidth_credential_attributes = BandwidthVoucher::new( + ¶ms, + BANDWIDTH_VALUE.to_string(), + network_defaults::VOUCHER_INFO.to_string(), + Hash::new([0; 32]), + // workaround for putting a valid value here, without deriving clone for the private + // key, until we have actual useful values + identity::PrivateKey::from_base58_string( + identity::KeyPair::new(&mut rng) + .private_key() + .to_base58_string(), + ) + .unwrap(), + encryption::KeyPair::new(&mut rng).private_key().clone(), + ); - let bandwidth_credential = obtain_signature( + let bandwidth_credential = obtain_aggregate_signature( ¶ms, &bandwidth_credential_attributes, &self.validator_endpoints, @@ -205,7 +212,7 @@ impl BandwidthController { #[cfg(not(feature = "coconut"))] pub async fn prepare_token_credential( &self, - gateway_identity: PublicKey, + gateway_identity: identity::PublicKey, gateway_owner: String, ) -> Result { let kp = match self.restore_keypair() { @@ -244,7 +251,7 @@ impl BandwidthController { #[cfg(not(feature = "coconut"))] pub async fn buy_token_credential( &self, - verification_key: PublicKey, + verification_key: identity::PublicKey, signed_verification_key: identity::Signature, gateway_owner: String, ) -> Result<(), GatewayClientError> { diff --git a/common/client-libs/validator-client/src/client.rs b/common/client-libs/validator-client/src/client.rs index 30af0ba8e0..fd9568e881 100644 --- a/common/client-libs/validator-client/src/client.rs +++ b/common/client-libs/validator-client/src/client.rs @@ -685,6 +685,16 @@ impl ApiClient { Ok(self.validator_api.blind_sign(request_body).await?) } + pub async fn partial_bandwidth_credential( + &self, + request_body: &str, + ) -> Result { + Ok(self + .validator_api + .partial_bandwidth_credential(request_body) + .await?) + } + pub async fn get_coconut_verification_key( &self, ) -> Result { diff --git a/common/client-libs/validator-client/src/nymd/mod.rs b/common/client-libs/validator-client/src/nymd/mod.rs index 0c7f81a5ae..216251b6f7 100644 --- a/common/client-libs/validator-client/src/nymd/mod.rs +++ b/common/client-libs/validator-client/src/nymd/mod.rs @@ -29,9 +29,12 @@ pub use crate::nymd::cosmwasm_client::client::CosmWasmClient; pub use crate::nymd::cosmwasm_client::signing_client::SigningCosmWasmClient; pub use crate::nymd::fee::Fee; use crate::nymd::fee::DEFAULT_SIMULATED_GAS_MULTIPLIER; +pub use cosmrs::rpc::endpoint::tx::Response as TxResponse; pub use cosmrs::rpc::endpoint::validators::Response as ValidatorResponse; pub use cosmrs::rpc::HttpClient as QueryNymdClient; pub use cosmrs::rpc::Paging; +pub use cosmrs::tendermint::abci::responses::{DeliverTx, Event}; +pub use cosmrs::tendermint::abci::tag::Tag; pub use cosmrs::tendermint::block::Height; pub use cosmrs::tendermint::hash; pub use cosmrs::tendermint::validator::Info as TendermintValidatorInfo; @@ -274,6 +277,13 @@ impl NymdClient { self.client.get_balance(address, denom).await } + pub async fn get_tx(&self, id: tx::Hash) -> Result + where + C: CosmWasmClient + Sync, + { + self.client.get_tx(id).await + } + pub async fn get_total_supply(&self) -> Result, NymdError> where C: CosmWasmClient + Sync, diff --git a/common/client-libs/validator-client/src/validator_api/error.rs b/common/client-libs/validator-client/src/validator_api/error.rs index b95865656c..02704e6229 100644 --- a/common/client-libs/validator-client/src/validator_api/error.rs +++ b/common/client-libs/validator-client/src/validator_api/error.rs @@ -7,4 +7,7 @@ pub enum ValidatorAPIError { #[from] source: reqwest::Error, }, + + #[error("Request failed with error message - {0}")] + GenericRequestFailure(String), } diff --git a/common/client-libs/validator-client/src/validator_api/mod.rs b/common/client-libs/validator-client/src/validator_api/mod.rs index ba737a3dfc..2e5646949c 100644 --- a/common/client-libs/validator-client/src/validator_api/mod.rs +++ b/common/client-libs/validator-client/src/validator_api/mod.rs @@ -14,7 +14,7 @@ use validator_api_requests::models::{ }; pub mod error; -pub(crate) mod routes; +pub mod routes; type PathSegments<'a> = &'a [&'a str]; type Params<'a, K, V> = &'a [(K, V)]; @@ -66,14 +66,14 @@ impl Client { V: AsRef, { let url = create_api_url(&self.url, path, params); - Ok(self - .reqwest_client - .post(url) - .json(json_body) - .send() - .await? - .json() - .await?) + let response = self.reqwest_client.post(url).json(json_body).send().await?; + if response.status().is_success() { + Ok(response.json().await?) + } else { + Err(ValidatorAPIError::GenericRequestFailure( + response.text().await?, + )) + } } pub async fn get_mixnodes(&self) -> Result, ValidatorAPIError> { @@ -254,7 +254,29 @@ impl Client { request_body: &BlindSignRequestBody, ) -> Result { self.post_validator_api( - &[routes::API_VERSION, routes::COCONUT_BLIND_SIGN], + &[ + routes::API_VERSION, + routes::COCONUT_ROUTES, + routes::BANDWIDTH, + routes::COCONUT_BLIND_SIGN, + ], + NO_PARAMS, + request_body, + ) + .await + } + + pub async fn partial_bandwidth_credential( + &self, + request_body: &str, + ) -> Result { + self.post_validator_api( + &[ + routes::API_VERSION, + routes::COCONUT_ROUTES, + routes::BANDWIDTH, + routes::COCONUT_PARTIAL_BANDWIDTH_CREDENTIAL, + ], NO_PARAMS, request_body, ) @@ -265,7 +287,12 @@ impl Client { &self, ) -> Result { self.query_validator_api( - &[routes::API_VERSION, routes::COCONUT_VERIFICATION_KEY], + &[ + routes::API_VERSION, + routes::COCONUT_ROUTES, + routes::BANDWIDTH, + routes::COCONUT_VERIFICATION_KEY, + ], NO_PARAMS, ) .await diff --git a/common/client-libs/validator-client/src/validator_api/routes.rs b/common/client-libs/validator-client/src/validator_api/routes.rs index e7785d4ec5..a21e61188f 100644 --- a/common/client-libs/validator-client/src/validator_api/routes.rs +++ b/common/client-libs/validator-client/src/validator_api/routes.rs @@ -10,7 +10,11 @@ pub const GATEWAYS: &str = "gateways"; pub const ACTIVE: &str = "active"; pub const REWARDED: &str = "rewarded"; +pub const COCONUT_ROUTES: &str = "coconut"; +pub const BANDWIDTH: &str = "bandwidth"; + pub const COCONUT_BLIND_SIGN: &str = "blind-sign"; +pub const COCONUT_PARTIAL_BANDWIDTH_CREDENTIAL: &str = "partial-bandwidth-credential"; pub const COCONUT_VERIFICATION_KEY: &str = "verification-key"; pub const STATUS_ROUTES: &str = "status"; diff --git a/common/coconut-interface/Cargo.toml b/common/coconut-interface/Cargo.toml index d2c891845d..285750cb3a 100644 --- a/common/coconut-interface/Cargo.toml +++ b/common/coconut-interface/Cargo.toml @@ -5,7 +5,9 @@ edition = "2021" description = "Crutch library until there is proper SerDe support for coconut structs" [dependencies] -serde = { version = "1.0", features = ["derive"] } +bs58 = "0.4.0" getset = "0.1.1" +serde = { version = "1.0", features = ["derive"] } +thiserror = "1" nymcoconut = {path = "../nymcoconut" } diff --git a/common/coconut-interface/src/error.rs b/common/coconut-interface/src/error.rs index f0632e937d..ee1d42ade5 100644 --- a/common/coconut-interface/src/error.rs +++ b/common/coconut-interface/src/error.rs @@ -5,21 +5,9 @@ use thiserror::Error; #[derive(Debug, Error)] pub enum CoconutInterfaceError { - #[error("could not parse validator URL: {source}")] - UrlParsingError { - #[from] - source: url::ParseError, - }, + #[error("not enough bytes: {0} received, minimum {1} required")] + InvalidByteLength(usize, usize), - #[error("could not aggregate verification key: {0}")] - AggregateVerificationKeyError(coconut_rs::CoconutError), - - #[error("could not prove credential: {0}")] - ProveCredentialError(coconut_rs::CoconutError), - - #[error("got invalid signature index: {0}")] - InvalidSignatureIdx(usize), - - #[error("got too many total attributes(public + private): {0} received, {1} is the maximum")] - TooManyTotalAttributes(usize, u32), + #[error("Could not decode base 58 string - {0}")] + MalformedString(#[from] bs58::decode::Error), } diff --git a/common/coconut-interface/src/lib.rs b/common/coconut-interface/src/lib.rs index a652422b82..1a6c6216f1 100644 --- a/common/coconut-interface/src/lib.rs +++ b/common/coconut-interface/src/lib.rs @@ -1,9 +1,13 @@ // Copyright 2021 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 +pub mod error; + use getset::{CopyGetters, Getters}; use serde::{Deserialize, Serialize}; +use error::CoconutInterfaceError; + pub use nymcoconut::*; #[derive(Serialize, Deserialize, Getters, CopyGetters, Clone)] @@ -79,27 +83,39 @@ impl VerifyCredentialBody { } } // All strings are base58 encoded representations of structs -#[derive(Serialize, Deserialize, Debug, Getters, CopyGetters)] +#[derive(Clone, Serialize, Deserialize, Debug, Getters, CopyGetters)] pub struct BlindSignRequestBody { #[getset(get = "pub")] blind_sign_request: BlindSignRequest, + #[getset(get = "pub")] + tx_hash: String, + #[getset(get = "pub")] + signature: String, public_attributes: Vec, #[getset(get = "pub")] + public_attributes_plain: Vec, + #[getset(get = "pub")] total_params: u32, } impl BlindSignRequestBody { pub fn new( blind_sign_request: &BlindSignRequest, + tx_hash: String, + signature: String, public_attributes: &[Attribute], + public_attributes_plain: Vec, total_params: u32, ) -> BlindSignRequestBody { BlindSignRequestBody { blind_sign_request: blind_sign_request.clone(), + tx_hash, + signature, public_attributes: public_attributes .iter() .map(|attr| attr.to_bs58()) .collect(), + public_attributes_plain, total_params, } } @@ -112,14 +128,46 @@ impl BlindSignRequestBody { } } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct BlindedSignatureResponse { - pub blinded_signature: BlindedSignature, + pub remote_key: [u8; 32], + pub encrypted_signature: Vec, } impl BlindedSignatureResponse { - pub fn new(blinded_signature: BlindedSignature) -> BlindedSignatureResponse { - BlindedSignatureResponse { blinded_signature } + pub fn new(encrypted_signature: Vec, remote_key: [u8; 32]) -> BlindedSignatureResponse { + BlindedSignatureResponse { + encrypted_signature, + remote_key, + } + } + + pub fn to_base58_string(&self) -> String { + bs58::encode(&self.to_bytes()).into_string() + } + + pub fn from_base58_string>(val: I) -> Result { + let bytes = bs58::decode(val).into_vec()?; + Self::from_bytes(&bytes) + } + + pub fn to_bytes(&self) -> Vec { + let mut bytes = self.remote_key.to_vec(); + bytes.extend_from_slice(&self.encrypted_signature); + bytes + } + + pub fn from_bytes(bytes: &[u8]) -> Result { + if bytes.len() < 32 { + return Err(CoconutInterfaceError::InvalidByteLength(bytes.len(), 32)); + } + let mut remote_key = [0u8; 32]; + remote_key.copy_from_slice(&bytes[..32]); + let encrypted_signature = bytes[32..].to_vec(); + Ok(BlindedSignatureResponse { + remote_key, + encrypted_signature, + }) } } diff --git a/common/cosmwasm-smart-contracts/coconut-bandwidth-contract/Cargo.toml b/common/cosmwasm-smart-contracts/coconut-bandwidth-contract/Cargo.toml new file mode 100644 index 0000000000..22803dc18d --- /dev/null +++ b/common/cosmwasm-smart-contracts/coconut-bandwidth-contract/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "coconut-bandwidth-contract-common" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +schemars = "0.8" +serde = { version = "1.0.103", default-features = false, features = ["derive"] } diff --git a/common/cosmwasm-smart-contracts/coconut-bandwidth-contract/src/deposit.rs b/common/cosmwasm-smart-contracts/coconut-bandwidth-contract/src/deposit.rs new file mode 100644 index 0000000000..a6b347042e --- /dev/null +++ b/common/cosmwasm-smart-contracts/coconut-bandwidth-contract/src/deposit.rs @@ -0,0 +1,34 @@ +// Copyright 2021 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct DepositData { + deposit_info: String, + identity_key: String, + encryption_key: String, +} + +impl DepositData { + pub fn new(deposit_info: String, identity_key: String, encryption_key: String) -> Self { + DepositData { + deposit_info, + identity_key, + encryption_key, + } + } + + pub fn deposit_info(&self) -> &str { + &self.deposit_info + } + + pub fn identity_key(&self) -> &str { + &self.identity_key + } + + pub fn encryption_key(&self) -> &str { + &self.encryption_key + } +} diff --git a/common/cosmwasm-smart-contracts/coconut-bandwidth-contract/src/events.rs b/common/cosmwasm-smart-contracts/coconut-bandwidth-contract/src/events.rs new file mode 100644 index 0000000000..5204f6a97e --- /dev/null +++ b/common/cosmwasm-smart-contracts/coconut-bandwidth-contract/src/events.rs @@ -0,0 +1,11 @@ +// Copyright 2021 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +// event types +pub const DEPOSITED_FUNDS_EVENT_TYPE: &str = "deposited-funds"; + +// attributes that are used in multiple places +pub const DEPOSIT_VALUE: &str = "deposit-value"; +pub const DEPOSIT_INFO: &str = "deposit-info"; +pub const DEPOSIT_IDENTITY_KEY: &str = "deposit-identity-key"; +pub const DEPOSIT_ENCRYPTION_KEY: &str = "deposit-encryption-key"; diff --git a/common/cosmwasm-smart-contracts/coconut-bandwidth-contract/src/lib.rs b/common/cosmwasm-smart-contracts/coconut-bandwidth-contract/src/lib.rs new file mode 100644 index 0000000000..b9afd74b5e --- /dev/null +++ b/common/cosmwasm-smart-contracts/coconut-bandwidth-contract/src/lib.rs @@ -0,0 +1,3 @@ +pub mod deposit; +pub mod events; +pub mod msg; diff --git a/common/cosmwasm-smart-contracts/coconut-bandwidth-contract/src/msg.rs b/common/cosmwasm-smart-contracts/coconut-bandwidth-contract/src/msg.rs new file mode 100644 index 0000000000..54679992e7 --- /dev/null +++ b/common/cosmwasm-smart-contracts/coconut-bandwidth-contract/src/msg.rs @@ -0,0 +1,24 @@ +// Copyright 2021 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +use crate::deposit::DepositData; + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct InstantiateMsg {} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum ExecuteMsg { + DepositFunds { data: DepositData }, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum QueryMsg {} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub struct MigrateMsg {} diff --git a/common/credentials/Cargo.toml b/common/credentials/Cargo.toml index 9c99137185..b7266becfa 100644 --- a/common/credentials/Cargo.toml +++ b/common/credentials/Cargo.toml @@ -7,11 +7,18 @@ edition = "2021" [dependencies] bls12_381 = { version = "0.5", default-features = false, features = ["pairings", "alloc", "experimental"] } +cosmrs = { version = "0.4.1", optional = true } thiserror = "1.0" url = "2.2" # I guess temporarily until we get serde support in coconut up and running coconut-interface = { path = "../coconut-interface" } -crypto = { path = "../crypto", features = ["asymmetric"] } +crypto = { path = "../crypto", features = ["rand", "asymmetric", "symmetric", "hashing"] } network-defaults = { path = "../network-defaults" } validator-client = { path = "../client-libs/validator-client" } + +[dev-dependencies] +rand = "0.7.3" + +[features] +coconut = ["cosmrs"] \ No newline at end of file diff --git a/common/credentials/src/coconut/bandwidth.rs b/common/credentials/src/coconut/bandwidth.rs index cb72374b6c..8cc95f3123 100644 --- a/common/credentials/src/coconut/bandwidth.rs +++ b/common/credentials/src/coconut/bandwidth.rs @@ -7,56 +7,167 @@ // it's the simplest possible case use coconut_interface::{ - Credential, Parameters, PrivateAttribute, PublicAttribute, Signature, VerificationKey, + hash_to_scalar, prepare_blind_sign, Attribute, BlindSignRequest, Credential, Parameters, + PrivateAttribute, PublicAttribute, Signature, VerificationKey, }; +use crypto::asymmetric::{encryption, identity}; use network_defaults::BANDWIDTH_VALUE; -use url::Url; +use cosmrs::tx::Hash; + +use super::utils::prepare_credential_for_spending; use crate::error::Error; -use super::utils::{obtain_aggregate_signature, prepare_credential_for_spending}; - pub const PUBLIC_ATTRIBUTES: u32 = 2; pub const PRIVATE_ATTRIBUTES: u32 = 2; pub const TOTAL_ATTRIBUTES: u32 = PUBLIC_ATTRIBUTES + PRIVATE_ATTRIBUTES; -pub struct BandwidthVoucherAttributes { +pub struct BandwidthVoucher { // a random secret value generated by the client used for double-spending detection - pub serial_number: PrivateAttribute, + serial_number: PrivateAttribute, // a random secret value generated by the client used to bind multiple credentials together - pub binding_number: PrivateAttribute, + binding_number: PrivateAttribute, // the value (e.g., bandwidth) encoded in this voucher - pub voucher_value: PublicAttribute, + voucher_value: PublicAttribute, + // the plain text value (e.g., bandwidth) encoded in this voucher + voucher_value_plain: String, // a field with public information, e.g., type of voucher, interval etc. - pub voucher_info: PublicAttribute, + voucher_info: PublicAttribute, + // the plain text information + voucher_info_plain: String, + // the hash of the deposit transaction + tx_hash: Hash, + // base58 encoded private key ensuring the depositer requested these attributes + signing_key: identity::PrivateKey, + // base58 encoded private key ensuring only this client receives the signature share + encryption_key: encryption::PrivateKey, + pedersen_commitments_openings: Vec, + blind_sign_request: BlindSignRequest, + use_request: bool, } -impl BandwidthVoucherAttributes { +impl BandwidthVoucher { + pub fn new_with_blind_sign_req( + private_attributes: [PrivateAttribute; PRIVATE_ATTRIBUTES as usize], + public_attributes_plain: [&str; PUBLIC_ATTRIBUTES as usize], + tx_hash: Hash, + signing_key: identity::PrivateKey, + encryption_key: encryption::PrivateKey, + pedersen_commitments_openings: Vec, + blind_sign_request: BlindSignRequest, + ) -> Self { + let voucher_value = public_attributes_plain[0]; + let voucher_info = public_attributes_plain[1]; + let voucher_value_plain = voucher_value.to_string(); + let voucher_info_plain = voucher_info.to_string(); + let voucher_value = hash_to_scalar(voucher_value.as_bytes()); + let voucher_info = hash_to_scalar(voucher_info.as_bytes()); + + BandwidthVoucher { + serial_number: private_attributes[0], + binding_number: private_attributes[1], + voucher_value, + voucher_value_plain, + voucher_info, + voucher_info_plain, + tx_hash, + signing_key, + encryption_key, + pedersen_commitments_openings, + blind_sign_request, + use_request: false, + } + } + pub fn new( + params: &Parameters, + voucher_value: String, + voucher_info: String, + tx_hash: Hash, + signing_key: identity::PrivateKey, + encryption_key: encryption::PrivateKey, + ) -> Self { + let serial_number = params.random_scalar(); + let binding_number = params.random_scalar(); + let voucher_value_plain = voucher_value.clone(); + let voucher_info_plain = voucher_info.clone(); + let voucher_value = hash_to_scalar(voucher_value.as_bytes()); + let voucher_info = hash_to_scalar(voucher_info.as_bytes()); + let (pedersen_commitments_openings, blind_sign_request) = prepare_blind_sign( + params, + &[serial_number, binding_number], + &[voucher_value, voucher_info], + ) + .unwrap(); + BandwidthVoucher { + serial_number, + binding_number, + voucher_value, + voucher_value_plain, + voucher_info, + voucher_info_plain, + tx_hash, + signing_key, + encryption_key, + pedersen_commitments_openings, + blind_sign_request, + use_request: true, + } + } + + /// Check if the plain values correspond to the PublicAttributes + 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]) + } + + pub fn tx_hash(&self) -> &Hash { + &self.tx_hash + } + pub fn get_public_attributes(&self) -> Vec { vec![self.voucher_value, self.voucher_info] } + pub fn encryption_key(&self) -> &encryption::PrivateKey { + &self.encryption_key + } + + pub fn pedersen_commitments_openings(&self) -> &Vec { + &self.pedersen_commitments_openings + } + + pub fn blind_sign_request(&self) -> &BlindSignRequest { + &self.blind_sign_request + } + + pub fn use_request(&self) -> bool { + self.use_request + } + + pub fn get_public_attributes_plain(&self) -> Vec { + vec![ + self.voucher_value_plain.clone(), + self.voucher_info_plain.clone(), + ] + } + pub fn get_private_attributes(&self) -> Vec { vec![self.serial_number, self.binding_number] } -} -// TODO: this definitely has to be moved somewhere else. It's just a temporary solution -pub async fn obtain_signature( - params: &Parameters, - attributes: &BandwidthVoucherAttributes, - validators: &[Url], -) -> Result { - let public_attributes = attributes.get_public_attributes(); - let private_attributes = attributes.get_private_attributes(); - - obtain_aggregate_signature(params, &public_attributes, &private_attributes, validators).await + pub fn sign(&self, request: &BlindSignRequest) -> identity::Signature { + let mut message = request.to_bytes(); + message.extend_from_slice(self.tx_hash.as_bytes()); + self.signing_key.sign(&message) + } } pub fn prepare_for_spending( raw_identity: &[u8], signature: &Signature, - attributes: &BandwidthVoucherAttributes, + attributes: &BandwidthVoucher, verification_key: &VerificationKey, ) -> Result { let public_attributes = vec![ @@ -75,3 +186,62 @@ pub fn prepare_for_spending( verification_key, ) } + +#[cfg(test)] +mod test { + use super::*; + use rand::rngs::OsRng; + + #[test] + fn voucher_consistency() { + let params = Parameters::new(4).unwrap(); + let mut rng = OsRng; + let voucher = BandwidthVoucher::new( + ¶ms, + "1234".to_string(), + "voucher info".to_string(), + Hash::new([0; 32]), + identity::PrivateKey::from_base58_string( + identity::KeyPair::new(&mut rng) + .private_key() + .to_base58_string(), + ) + .unwrap(), + encryption::KeyPair::new(&mut rng).private_key().clone(), + ); + assert!(!BandwidthVoucher::verify_against_plain( + &[], + &voucher.get_public_attributes_plain() + )); + assert!(!BandwidthVoucher::verify_against_plain( + &voucher.get_public_attributes(), + &vec![], + )); + assert!(!BandwidthVoucher::verify_against_plain( + &voucher.get_public_attributes(), + &[ + voucher.get_public_attributes_plain()[0].clone(), + String::new() + ] + )); + assert!(!BandwidthVoucher::verify_against_plain( + &voucher.get_public_attributes(), + &[ + String::new(), + voucher.get_public_attributes_plain()[1].clone() + ] + )); + assert!(!BandwidthVoucher::verify_against_plain( + &[voucher.get_public_attributes()[0], Attribute::one()], + &voucher.get_public_attributes_plain() + )); + assert!(!BandwidthVoucher::verify_against_plain( + &[Attribute::one(), voucher.get_public_attributes()[1]], + &voucher.get_public_attributes_plain() + )); + assert!(BandwidthVoucher::verify_against_plain( + &voucher.get_public_attributes(), + &voucher.get_public_attributes_plain() + )); + } +} diff --git a/common/credentials/src/coconut/mod.rs b/common/credentials/src/coconut/mod.rs index bf480ad58a..c1d900689a 100644 --- a/common/credentials/src/coconut/mod.rs +++ b/common/credentials/src/coconut/mod.rs @@ -2,4 +2,5 @@ // SPDX-License-Identifier: Apache-2.0 pub mod bandwidth; +pub mod params; pub mod utils; diff --git a/common/credentials/src/coconut/params.rs b/common/credentials/src/coconut/params.rs new file mode 100644 index 0000000000..42b9205ebb --- /dev/null +++ b/common/credentials/src/coconut/params.rs @@ -0,0 +1,15 @@ +// Copyright 2022 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crypto::aes::Aes128; +use crypto::blake3; +use crypto::ctr; + +type Aes128Ctr = ctr::Ctr64LE; + +/// Hashing algorithm used during hkdf for ephemeral shared key generation per blinded signature +/// response encryption. +pub type ValidatorApiCredentialHkdfAlgorithm = blake3::Hasher; + +/// Encryption algorithm used for end-to-end encryption of blinded signature response +pub type ValidatorApiCredentialEncryptionAlgorithm = Aes128Ctr; diff --git a/common/credentials/src/coconut/utils.rs b/common/credentials/src/coconut/utils.rs index 9d451736a9..7b61f70158 100644 --- a/common/credentials/src/coconut/utils.rs +++ b/common/credentials/src/coconut/utils.rs @@ -1,15 +1,20 @@ // Copyright 2021 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use bls12_381::Scalar; use coconut_interface::{ - aggregate_signature_shares, aggregate_verification_keys, prepare_blind_sign, - prove_bandwidth_credential, Attribute, BlindSignRequest, BlindSignRequestBody, Credential, - Parameters, Signature, SignatureShare, VerificationKey, + aggregate_signature_shares, aggregate_verification_keys, prove_bandwidth_credential, Attribute, + BlindSignRequestBody, BlindedSignature, Credential, Parameters, Signature, SignatureShare, + VerificationKey, }; +use crypto::asymmetric::encryption::PublicKey; +use crypto::shared_key::recompute_shared_key; +use crypto::symmetric::stream_cipher; use url::Url; -use crate::coconut::bandwidth::PRIVATE_ATTRIBUTES; +use crate::coconut::bandwidth::{BandwidthVoucher, PRIVATE_ATTRIBUTES}; +use crate::coconut::params::{ + ValidatorApiCredentialEncryptionAlgorithm, ValidatorApiCredentialHkdfAlgorithm, +}; use crate::error::Error; /// Contacts all provided validators and then aggregate their verification keys. @@ -63,31 +68,53 @@ pub async fn obtain_aggregate_verification_key( async fn obtain_partial_credential( params: &Parameters, - public_attributes: &[Attribute], - private_attributes: &[Attribute], - pedersen_commitments_openings: &[Scalar], - blind_sign_request: &BlindSignRequest, + attributes: &BandwidthVoucher, client: &validator_client::ApiClient, validator_vk: &VerificationKey, ) -> Result { - let blind_sign_request_body = BlindSignRequestBody::new( - blind_sign_request, - public_attributes, - (public_attributes.len() + private_attributes.len()) as u32, + 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 response = if attributes.use_request() { + let blind_sign_request_body = BlindSignRequestBody::new( + blind_sign_request, + attributes.tx_hash().to_string(), + attributes.sign(blind_sign_request).to_base58_string(), + &public_attributes, + public_attributes_plain, + (public_attributes.len() + private_attributes.len()) as u32, + ); + client.blind_sign(&blind_sign_request_body).await? + } else { + client + .partial_bandwidth_credential(&attributes.tx_hash().to_string()) + .await? + }; + let encrypted_signature = response.encrypted_signature; + let remote_key = PublicKey::from_bytes(&response.remote_key)?; + + let encryption_key = recompute_shared_key::< + ValidatorApiCredentialEncryptionAlgorithm, + ValidatorApiCredentialHkdfAlgorithm, + >(&remote_key, attributes.encryption_key()); + let zero_iv = stream_cipher::zero_iv::(); + let blinded_signature_bytes = stream_cipher::decrypt::( + &encryption_key, + &zero_iv, + &encrypted_signature, ); - let blinded_signature = client - .blind_sign(&blind_sign_request_body) - .await? - .blinded_signature; + let blinded_signature = BlindedSignature::from_bytes(&blinded_signature_bytes)?; let unblinded_signature = blinded_signature.unblind( params, validator_vk, - private_attributes, - public_attributes, + &private_attributes, + &public_attributes, &blind_sign_request.get_commitment_hash(), - &*pedersen_commitments_openings, + attributes.pedersen_commitments_openings(), )?; Ok(unblinded_signature) @@ -95,13 +122,14 @@ async fn obtain_partial_credential( pub async fn obtain_aggregate_signature( params: &Parameters, - public_attributes: &[Attribute], - private_attributes: &[Attribute], + attributes: &BandwidthVoucher, validators: &[Url], ) -> Result { if validators.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(validators.len()); let mut validators_partial_vks: Vec = Vec::with_capacity(validators.len()); @@ -110,42 +138,24 @@ pub async fn obtain_aggregate_signature( let validator_partial_vk = client.get_coconut_verification_key().await?; validators_partial_vks.push(validator_partial_vk.key.clone()); - let (pedersen_commitments_openings, blind_sign_request) = - prepare_blind_sign(params, private_attributes, public_attributes)?; - - let first = obtain_partial_credential( - params, - public_attributes, - private_attributes, - &pedersen_commitments_openings, - &blind_sign_request, - &client, - &validator_partial_vk.key, - ) - .await?; + let first = + obtain_partial_credential(params, attributes, &client, &validator_partial_vk.key).await?; shares.push(SignatureShare::new(first, 1)); for (id, validator_url) in validators.iter().enumerate().skip(1) { client.change_validator_api(validator_url.clone()); let validator_partial_vk = client.get_coconut_verification_key().await?; validators_partial_vks.push(validator_partial_vk.key.clone()); - let signature = obtain_partial_credential( - params, - public_attributes, - private_attributes, - &pedersen_commitments_openings, - &blind_sign_request, - &client, - &validator_partial_vk.key, - ) - .await?; + let signature = + obtain_partial_credential(params, attributes, &client, &validator_partial_vk.key) + .await?; let share = SignatureShare::new(signature, (id + 1) as u64); shares.push(share) } let mut attributes = Vec::with_capacity(private_attributes.len() + public_attributes.len()); - attributes.extend_from_slice(private_attributes); - attributes.extend_from_slice(public_attributes); + attributes.extend_from_slice(&private_attributes); + attributes.extend_from_slice(&public_attributes); let mut indices: Vec = Vec::with_capacity(validators_partial_vks.len()); for i in 0..validators_partial_vks.len() { diff --git a/common/credentials/src/error.rs b/common/credentials/src/error.rs index f2161ca9ac..e67e74f254 100644 --- a/common/credentials/src/error.rs +++ b/common/credentials/src/error.rs @@ -1,10 +1,13 @@ // Copyright 2021 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 +#[cfg(feature = "coconut")] use coconut_interface::CoconutError; -use thiserror::Error; +use crypto::asymmetric::encryption::KeyRecoveryError; use validator_client::ValidatorClientError; +use thiserror::Error; + #[derive(Debug, Error)] pub enum Error { #[error("The detailed description is yet to be determined")] @@ -13,6 +16,7 @@ pub enum Error { #[error("Could not contact any validator")] NoValidatorsAvailable, + #[cfg(feature = "coconut")] #[error("Run into a coconut error - {0}")] CoconutError(#[from] CoconutError), @@ -30,4 +34,7 @@ pub enum Error { #[error("There is not associated bandwidth for the given client")] MissingBandwidth, + + #[error("Could not parse the key - {0}")] + ParsePublicKey(#[from] KeyRecoveryError), } diff --git a/common/credentials/src/lib.rs b/common/credentials/src/lib.rs index 436f788261..5eb08ed817 100644 --- a/common/credentials/src/lib.rs +++ b/common/credentials/src/lib.rs @@ -1,8 +1,11 @@ // Copyright 2021 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 +#[cfg(feature = "coconut")] pub mod coconut; pub mod error; +#[cfg(not(feature = "coconut"))] pub mod token; +#[cfg(feature = "coconut")] pub use coconut::utils::{obtain_aggregate_signature, obtain_aggregate_verification_key}; diff --git a/common/credentials/src/token/bandwidth.rs b/common/credentials/src/token/bandwidth.rs index 79ed4cc9aa..c3e6124160 100644 --- a/common/credentials/src/token/bandwidth.rs +++ b/common/credentials/src/token/bandwidth.rs @@ -6,7 +6,6 @@ use crypto::asymmetric::identity::{PublicKey, Signature, PUBLIC_KEY_LENGTH, SIGN use crate::error::Error; use std::convert::TryInto; -#[cfg(not(feature = "coconut"))] pub struct TokenCredential { verification_key: PublicKey, gateway_identity: PublicKey, @@ -14,7 +13,6 @@ pub struct TokenCredential { signature: Signature, } -#[cfg(not(feature = "coconut"))] impl TokenCredential { pub fn new( verification_key: PublicKey, @@ -99,7 +97,6 @@ impl TokenCredential { mod tests { use super::*; - #[cfg(not(feature = "coconut"))] #[test] fn token_serde() { // pre-generated, valid values diff --git a/common/network-defaults/src/lib.rs b/common/network-defaults/src/lib.rs index 194b64736c..dc55029d6c 100644 --- a/common/network-defaults/src/lib.rs +++ b/common/network-defaults/src/lib.rs @@ -147,6 +147,8 @@ pub const UTOKENS_TO_BURN: u64 = TOKENS_TO_BURN * 1000000; /// Default bandwidth (in bytes) that we try to buy pub const BANDWIDTH_VALUE: u64 = TOKENS_TO_BURN * BYTES_PER_TOKEN; +pub const VOUCHER_INFO: &str = "BandwidthVoucher"; + pub const ETH_MIN_BLOCK_DEPTH: usize = 7; /// Defaults Cosmos Hub/ATOM path diff --git a/common/nymcoconut/src/lib.rs b/common/nymcoconut/src/lib.rs index 491a8e8fe1..936b27005f 100644 --- a/common/nymcoconut/src/lib.rs +++ b/common/nymcoconut/src/lib.rs @@ -5,6 +5,7 @@ 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,8 +29,6 @@ pub use scheme::SignatureShare; pub use traits::Base58; pub use utils::hash_to_scalar; -use crate::traits::Bytable; - pub mod elgamal; mod error; mod impls; diff --git a/contracts/Cargo.lock b/contracts/Cargo.lock index 9758571507..9e5ee6baee 100644 --- a/contracts/Cargo.lock +++ b/contracts/Cargo.lock @@ -191,6 +191,28 @@ dependencies = [ "generic-array 0.14.5", ] +[[package]] +name = "coconut-bandwidth" +version = "0.1.0" +dependencies = [ + "bandwidth-claim-contract", + "coconut-bandwidth-contract-common", + "config", + "cosmwasm-std", + "cosmwasm-storage", + "schemars", + "serde", + "thiserror", +] + +[[package]] +name = "coconut-bandwidth-contract-common" +version = "0.1.0" +dependencies = [ + "schemars", + "serde", +] + [[package]] name = "config" version = "0.1.0" diff --git a/contracts/Cargo.toml b/contracts/Cargo.toml index f638b6ad67..d748532df6 100644 --- a/contracts/Cargo.toml +++ b/contracts/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["bandwidth-claim", "mixnet", "vesting"] +members = ["bandwidth-claim", "coconut-bandwidth", "mixnet", "vesting"] [profile.release] opt-level = 3 diff --git a/contracts/coconut-bandwidth/Cargo.lock b/contracts/coconut-bandwidth/Cargo.lock new file mode 100644 index 0000000000..adc969f5a1 --- /dev/null +++ b/contracts/coconut-bandwidth/Cargo.lock @@ -0,0 +1,867 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +dependencies = [ + "block-padding", + "byte-tools", + "byteorder", + "generic-array 0.12.4", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array 0.14.4", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +dependencies = [ + "byte-tools", +] + +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "config" +version = "0.1.0" +dependencies = [ + "handlebars", + "humantime-serde", + "network-defaults", + "serde", + "toml", + "url", +] + +[[package]] +name = "const-oid" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdab415d6744056100f40250a66bc430c1a46f7a02e20bc11c94c79a0f0464df" + +[[package]] +name = "cosmos_contract" +version = "0.1.0" +dependencies = [ + "config", + "cosmwasm-std", + "cosmwasm-storage", + "erc20-bridge-contract", + "schemars", + "serde", + "thiserror", +] + +[[package]] +name = "cosmwasm-crypto" +version = "1.0.0-beta2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c16b255449b3f5cd7fa4b79acd5225b5185655261087a3d8aaac44f88a0e23e9" +dependencies = [ + "digest 0.9.0", + "ed25519-zebra", + "k256", + "rand_core 0.5.1", + "thiserror", +] + +[[package]] +name = "cosmwasm-derive" +version = "1.0.0-beta2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abad1a6ff427a2f66890a4dce6354b4563cd07cee91a942300e011c921c09ed2" +dependencies = [ + "syn", +] + +[[package]] +name = "cosmwasm-std" +version = "1.0.0-beta2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1660ee3d5734672e1eb4f0ceda403e2d83345e15143a48845f340f3252ce99a6" +dependencies = [ + "base64", + "cosmwasm-crypto", + "cosmwasm-derive", + "schemars", + "serde", + "serde-json-wasm", + "thiserror", + "uint", +] + +[[package]] +name = "cosmwasm-storage" +version = "1.0.0-beta2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3b4efe3b4f86df668520a02e9a29c23eea99b64dfcacb0e59b98346418af7f" +dependencies = [ + "cosmwasm-std", + "serde", +] + +[[package]] +name = "cpufeatures" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" +dependencies = [ + "libc", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d12477e115c0d570c12a2dfd859f80b55b60ddb5075df210d3af06d133a69f45" +dependencies = [ + "generic-array 0.14.4", + "rand_core 0.6.3", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-mac" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +dependencies = [ + "generic-array 0.14.4", + "subtle", +] + +[[package]] +name = "curve25519-dalek" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "der" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28e98c534e9c8a0483aa01d6f6913bc063de254311bd267c9cf535e9b70e15b2" +dependencies = [ + "const-oid", +] + +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array 0.12.4", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array 0.14.4", +] + +[[package]] +name = "dyn-clone" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee2626afccd7561a06cf1367e2950c4718ea04565e20fb5029b6c7d8ad09abcf" + +[[package]] +name = "ecdsa" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43ee23aa5b4f68c7a092b5c3beb25f50c406adc75e2363634f242f28ab255372" +dependencies = [ + "der", + "elliptic-curve", + "hmac", + "signature", +] + +[[package]] +name = "ed25519-zebra" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a128b76af6dd4b427e34a6fd43dc78dbfe73672ec41ff615a2414c1a0ad0409" +dependencies = [ + "curve25519-dalek", + "hex", + "rand_core 0.5.1", + "serde", + "sha2", + "thiserror", +] + +[[package]] +name = "elliptic-curve" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "beca177dcb8eb540133e7680baff45e7cc4d93bf22002676cec549f82343721b" +dependencies = [ + "crypto-bigint", + "ff", + "generic-array 0.14.4", + "group", + "pkcs8", + "rand_core 0.6.3", + "subtle", + "zeroize", +] + +[[package]] +name = "erc20-bridge-contract" +version = "0.1.0" +dependencies = [ + "schemars", + "serde", +] + +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" + +[[package]] +name = "ff" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0f40b2dcd8bc322217a5f6559ae5f9e9d1de202a2ecee2e9eafcbece7562a4f" +dependencies = [ + "rand_core 0.6.3", + "subtle", +] + +[[package]] +name = "form_urlencoded" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + +[[package]] +name = "generic-array" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" +dependencies = [ + "typenum", +] + +[[package]] +name = "generic-array" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.10.2+wasi-snapshot-preview1", +] + +[[package]] +name = "group" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c363a5301b8f153d80747126a04b3c82073b9fe3130571a9d170cacdeaf7912" +dependencies = [ + "ff", + "rand_core 0.6.3", + "subtle", +] + +[[package]] +name = "handlebars" +version = "3.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4498fc115fa7d34de968184e473529abb40eeb6be8bc5f7faba3d08c316cb3e3" +dependencies = [ + "log", + "pest", + "pest_derive", + "quick-error", + "serde", + "serde_json", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hex-literal" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21e4590e13640f19f249fe3e4eca5113bc4289f2497710378190e7f4bd96f45b" + +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "humantime-serde" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac34a56cfd4acddb469cc7fff187ed5ac36f498ba085caf8bbc725e3ff474058" +dependencies = [ + "humantime", + "serde", +] + +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + +[[package]] +name = "k256" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "903ae2481bcdfdb7b68e0a9baa4b7c9aff600b9ae2e8e5bb5833b8c91ab851ea" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "sha2", +] + +[[package]] +name = "libc" +version = "0.2.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6" + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "network-defaults" +version = "0.1.0" +dependencies = [ + "hex-literal", + "serde", + "time", + "url", +] + +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pest" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +dependencies = [ + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" +dependencies = [ + "maplit", + "pest", + "sha-1", +] + +[[package]] +name = "pkcs8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee3ef9b64d26bad0536099c816c6734379e45bbd5f14798def6809e5cc350447" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "proc-macro2" +version = "1.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + +[[package]] +name = "quote" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom 0.2.3", +] + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + +[[package]] +name = "schemars" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a48d098c2a7fdf5740b19deb1181b4fb8a9e68e03ae517c14cde04b5725409" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9ea2a613fe4cd7118b2bb101a25d8ae6192e1975179b67b2f17afd11e70ac8" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn", +] + +[[package]] +name = "serde" +version = "1.0.130" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-json-wasm" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50eef3672ec8fa45f3457fd423ba131117786784a895548021976117c1ded449" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.130" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_derive_internals" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dbab34ca63057a1f15280bdf3c39f2b1eb1b54c17e98360e511637aef7418c6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha-1" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" +dependencies = [ + "block-buffer 0.7.3", + "digest 0.8.1", + "fake-simd", + "opaque-debug 0.2.3", +] + +[[package]] +name = "sha2" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + +[[package]] +name = "signature" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c19772be3c4dd2ceaacf03cb41d5885f2a02c4d8804884918e3a258480803335" +dependencies = [ + "digest 0.9.0", + "rand_core 0.6.3", +] + +[[package]] +name = "spki" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c01a0c15da1b0b0e1494112e7af814a678fec9bd157881b49beac661e9b6f32" +dependencies = [ + "der", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1d708c221c5a612956ef9f75b37e454e88d1f7b899fbd3a18d4252012d663" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "thiserror" +version = "1.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99beeb0daeac2bd1e86ac2c21caddecb244b39a093594da1a661ec2060c7aedd" +dependencies = [ + "libc", + "time-macros", +] + +[[package]] +name = "time-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25eb0ca3468fc0acc11828786797f6ef9aa1555e4a211a60d64cc8e4d1be47d6" + +[[package]] +name = "tinyvec" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83b2a3d4d9091d0abd7eba4dc2710b1718583bd4d8992e2190720ea38f391f7" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "toml" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +dependencies = [ + "serde", +] + +[[package]] +name = "typenum" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" + +[[package]] +name = "ucd-trie" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" + +[[package]] +name = "uint" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6470ab50f482bde894a037a57064480a246dbfdd5960bd65a44824693f08da5f" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" + +[[package]] +name = "unicode-normalization" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "url" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", +] + +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "zeroize" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" diff --git a/contracts/coconut-bandwidth/Cargo.toml b/contracts/coconut-bandwidth/Cargo.toml new file mode 100644 index 0000000000..234e5ced4b --- /dev/null +++ b/contracts/coconut-bandwidth/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "coconut-bandwidth" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] +bandwidth-claim-contract = { path = "../../common/bandwidth-claim-contract" } +coconut-bandwidth-contract-common = { path = "../../common/cosmwasm-smart-contracts/coconut-bandwidth-contract" } +config = { path = "../../common/config"} + +cosmwasm-std = "1.0.0-beta3" +cosmwasm-storage = "1.0.0-beta3" + +schemars = "0.8" +serde = { version = "1.0.103", default-features = false, features = ["derive"] } +thiserror = "1.0.23" diff --git a/contracts/coconut-bandwidth/src/error.rs b/contracts/coconut-bandwidth/src/error.rs new file mode 100644 index 0000000000..4c10be3783 --- /dev/null +++ b/contracts/coconut-bandwidth/src/error.rs @@ -0,0 +1,26 @@ +// Copyright 2021 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use cosmwasm_std::StdError; +use thiserror::Error; + +use config::defaults::DENOM; + +/// Custom errors for contract failure conditions. +/// +/// Add any other custom errors you like here. +/// Look at https://docs.rs/thiserror/1.0.21/thiserror/ for details. +#[derive(Error, Debug, PartialEq)] +pub enum ContractError { + #[error("{0}")] + Std(#[from] StdError), + + #[error("Received multiple coin types")] + MultipleDenoms, + + #[error("No coin was sent for voucher")] + NoCoin, + + #[error("Wrong coin denomination, you must send {}", DENOM)] + WrongDenom, +} diff --git a/contracts/coconut-bandwidth/src/lib.rs b/contracts/coconut-bandwidth/src/lib.rs new file mode 100644 index 0000000000..133ffb1999 --- /dev/null +++ b/contracts/coconut-bandwidth/src/lib.rs @@ -0,0 +1,73 @@ +// Copyright 2021 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +mod error; +mod support; +mod transactions; + +use cosmwasm_std::{entry_point, DepsMut, Env, MessageInfo, Response}; + +use crate::error::ContractError; +use coconut_bandwidth_contract_common::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg}; + +/// Instantiate the contract. +/// +/// `deps` contains Storage, API and Querier +/// `env` contains block, message and contract info +/// `msg` is the contract initialization message, sort of like a constructor call. +#[entry_point] +pub fn instantiate( + _deps: DepsMut<'_>, + _env: Env, + _info: MessageInfo, + _msg: InstantiateMsg, +) -> Result { + Ok(Response::default()) +} + +/// Handle an incoming message +#[entry_point] +pub fn execute( + deps: DepsMut<'_>, + env: Env, + info: MessageInfo, + msg: ExecuteMsg, +) -> Result { + match msg { + ExecuteMsg::DepositFunds { data } => transactions::deposit_funds(deps, env, info, data), + } +} + +#[entry_point] +pub fn migrate(_deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result { + Ok(Default::default()) +} + +#[cfg(test)] +mod tests { + use super::*; + use config::defaults::DENOM; + use cosmwasm_std::coins; + use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; + + #[test] + fn initialize_contract() { + let mut deps = mock_dependencies(); + let env = mock_env(); + let msg = InstantiateMsg {}; + let info = mock_info("creator", &[]); + + let res = instantiate(deps.as_mut(), env.clone(), info, msg).unwrap(); + assert_eq!(0, res.messages.len()); + + // Contract balance should be 0 + assert_eq!( + coins(0, DENOM), + vec![deps + .as_ref() + .querier + .query_balance(env.contract.address, DENOM) + .unwrap()] + ); + } +} diff --git a/contracts/coconut-bandwidth/src/support/mod.rs b/contracts/coconut-bandwidth/src/support/mod.rs new file mode 100644 index 0000000000..3e1ec563d5 --- /dev/null +++ b/contracts/coconut-bandwidth/src/support/mod.rs @@ -0,0 +1,3 @@ +// Copyright 2021 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 +pub mod tests; diff --git a/contracts/coconut-bandwidth/src/support/tests.rs b/contracts/coconut-bandwidth/src/support/tests.rs new file mode 100644 index 0000000000..352f75439b --- /dev/null +++ b/contracts/coconut-bandwidth/src/support/tests.rs @@ -0,0 +1,19 @@ +// Copyright 2021 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +#[cfg(test)] +pub mod helpers { + use crate::instantiate; + use coconut_bandwidth_contract_common::msg::InstantiateMsg; + use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info, MockApi, MockQuerier}; + use cosmwasm_std::{Empty, MemoryStorage, OwnedDeps}; + + pub fn init_contract() -> OwnedDeps> { + let mut deps = mock_dependencies(); + let msg = InstantiateMsg {}; + let env = mock_env(); + let info = mock_info("creator", &[]); + instantiate(deps.as_mut(), env.clone(), info, msg).unwrap(); + return deps; + } +} diff --git a/contracts/coconut-bandwidth/src/transactions.rs b/contracts/coconut-bandwidth/src/transactions.rs new file mode 100644 index 0000000000..202ff71bb2 --- /dev/null +++ b/contracts/coconut-bandwidth/src/transactions.rs @@ -0,0 +1,136 @@ +// Copyright 2021 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use cosmwasm_std::{DepsMut, Env, Event, MessageInfo, Response}; + +use crate::error::ContractError; +use coconut_bandwidth_contract_common::deposit::DepositData; +use coconut_bandwidth_contract_common::events::{ + DEPOSITED_FUNDS_EVENT_TYPE, DEPOSIT_ENCRYPTION_KEY, DEPOSIT_IDENTITY_KEY, DEPOSIT_INFO, + DEPOSIT_VALUE, +}; +use config::defaults::DENOM; + +pub(crate) fn deposit_funds( + _deps: DepsMut<'_>, + _env: Env, + info: MessageInfo, + data: DepositData, +) -> Result { + 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(DEPOSITED_FUNDS_EVENT_TYPE) + .add_attribute(DEPOSIT_VALUE, voucher_value.amount) + .add_attribute(DEPOSIT_INFO, data.deposit_info()) + .add_attribute(DEPOSIT_IDENTITY_KEY, data.identity_key()) + .add_attribute(DEPOSIT_ENCRYPTION_KEY, data.encryption_key()); + + Ok(Response::new().add_event(event)) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::support::tests::helpers; + use cosmwasm_std::testing::{mock_env, mock_info}; + use cosmwasm_std::Coin; + + #[test] + fn invalid_deposit() { + let mut deps = helpers::init_contract(); + let env = mock_env(); + let info = mock_info("requester", &[]); + + let deposit_info = String::from("Deposit info"); + let verification_key = String::from("Verification key"); + let encryption_key = String::from("Encryption key"); + let data = DepositData::new(deposit_info, verification_key, encryption_key); + + assert_eq!( + deposit_funds(deps.as_mut(), env.clone(), info, data.clone()), + Err(ContractError::NoCoin) + ); + + let coin = Coin::new(1000000, DENOM); + let second_coin = Coin::new(1000000, "some_denom"); + + let info = mock_info("requester", &[coin, second_coin.clone()]); + assert_eq!( + deposit_funds(deps.as_mut(), env.clone(), info, data.clone()), + Err(ContractError::MultipleDenoms) + ); + + let info = mock_info("requester", &[second_coin]); + assert_eq!( + deposit_funds(deps.as_mut(), env, info, data), + Err(ContractError::WrongDenom) + ); + } + + #[test] + fn valid_deposit() { + let mut deps = helpers::init_contract(); + let env = mock_env(); + + let deposit_info = String::from("Deposit info"); + let verification_key = String::from("Verification key"); + let encryption_key = String::from("Encryption key"); + let deposit_value = 424242; + let data = DepositData::new( + deposit_info.clone(), + verification_key.clone(), + encryption_key.clone(), + ); + let coin = Coin::new(deposit_value, DENOM); + let info = mock_info("requester", &[coin]); + + let tx = deposit_funds(deps.as_mut(), env.clone(), info, data).unwrap(); + + let events: Vec<_> = tx + .events + .iter() + .filter(|event| event.ty == DEPOSITED_FUNDS_EVENT_TYPE) + .collect(); + assert_eq!(events.len(), 1); + + let event = events[0]; + assert_eq!(event.attributes.len(), 4); + + let deposit_attr = event + .attributes + .iter() + .find(|attr| attr.key == DEPOSIT_VALUE) + .unwrap(); + assert_eq!(deposit_attr.value, deposit_value.to_string()); + + let info_attr = event + .attributes + .iter() + .find(|attr| attr.key == DEPOSIT_INFO) + .unwrap(); + assert_eq!(info_attr.value, deposit_info); + + let verification_key_attr = event + .attributes + .iter() + .find(|attr| attr.key == DEPOSIT_IDENTITY_KEY) + .unwrap(); + assert_eq!(verification_key_attr.value, verification_key); + + let encryption_key_attr = event + .attributes + .iter() + .find(|attr| attr.key == DEPOSIT_ENCRYPTION_KEY) + .unwrap(); + assert_eq!(encryption_key_attr.value, encryption_key); + } +} diff --git a/gateway/Cargo.toml b/gateway/Cargo.toml index 147cae6444..93ea3178fb 100644 --- a/gateway/Cargo.toml +++ b/gateway/Cargo.toml @@ -55,7 +55,7 @@ validator-client = { path = "../common/client-libs/validator-client", features = version-checker = { path = "../common/version-checker" } [features] -coconut = ["coconut-interface", "gateway-requests/coconut", "gateway-client/coconut"] +coconut = ["coconut-interface", "gateway-requests/coconut", "gateway-client/coconut", "credentials/coconut"] eth = [] [build-dependencies] diff --git a/gateway/gateway-requests/Cargo.toml b/gateway/gateway-requests/Cargo.toml index a835554d9b..2d0b46dd88 100644 --- a/gateway/gateway-requests/Cargo.toml +++ b/gateway/gateway-requests/Cargo.toml @@ -27,7 +27,7 @@ coconut-interface = { path = "../../common/coconut-interface", optional = true } credentials = { path = "../../common/credentials" } [features] -coconut = ["coconut-interface"] +coconut = ["coconut-interface", "credentials/coconut"] [dependencies.tungstenite] version = "0.13.0" diff --git a/validator-api/Cargo.toml b/validator-api/Cargo.toml index 0b606cd4aa..0eb27db044 100644 --- a/validator-api/Cargo.toml +++ b/validator-api/Cargo.toml @@ -15,6 +15,7 @@ rust-version = "1.56" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +async-trait = "0.1.52" clap = "2.33.0" dirs = "3.0" dotenv = "0.15.0" @@ -43,6 +44,7 @@ sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "sqlite", "macros" ## internal +coconut-bandwidth-contract-common = { path = "../common/cosmwasm-smart-contracts/coconut-bandwidth-contract" } config = { path = "../common/config" } crypto = { path="../common/crypto" } gateway-client = { path="../common/client-libs/gateway-client" } @@ -59,7 +61,7 @@ console-subscriber = { version = "0.1.1", optional = true} cfg-if = "1.0" [features] -coconut = ["coconut-interface", "credentials", "gateway-client/coconut"] +coconut = ["coconut-interface", "credentials", "gateway-client/coconut", "credentials/coconut"] no-reward = [] [build-dependencies] @@ -68,4 +70,5 @@ sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "sqlite", "macros" vergen = { version = "5", default-features = false, features = ["build", "git", "rustc", "cargo"] } [dev-dependencies] -attohttpc = {version = "0.18.0", features = ["json"]} \ No newline at end of file +attohttpc = {version = "0.18.0", features = ["json"]} +nymcoconut = { path = "../common/nymcoconut" } diff --git a/validator-api/migrations/20220325120000_signed_deposits.sql b/validator-api/migrations/20220325120000_signed_deposits.sql new file mode 100644 index 0000000000..e5e9c382be --- /dev/null +++ b/validator-api/migrations/20220325120000_signed_deposits.sql @@ -0,0 +1,6 @@ +CREATE TABLE signed_deposit +( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + tx_hash VARCHAR NOT NULL UNIQUE, + blinded_signature_response VARCHAR NOT NULL +); \ No newline at end of file diff --git a/validator-api/src/coconut/client.rs b/validator-api/src/coconut/client.rs new file mode 100644 index 0000000000..c61a7d474f --- /dev/null +++ b/validator-api/src/coconut/client.rs @@ -0,0 +1,35 @@ +// Copyright 2022 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::coconut::error::{CoconutError, Result}; +use crate::config::DEFAULT_LOCAL_VALIDATOR; + +use validator_client::nymd::{tx::Hash, NymdClient, QueryNymdClient, TxResponse}; + +use async_trait::async_trait; + +#[async_trait] +pub trait Client { + async fn get_tx(&self, tx_hash: &str) -> Result; +} + +pub struct QueryClient { + inner: NymdClient, +} + +impl QueryClient { + pub fn new() -> Result { + let inner = NymdClient::connect(DEFAULT_LOCAL_VALIDATOR, None, None, None)?; + Ok(Self { inner }) + } +} + +#[async_trait] +impl Client for QueryClient { + async fn get_tx(&self, tx_hash: &str) -> Result { + let tx_hash = tx_hash + .parse::() + .map_err(|_| CoconutError::TxHashParseError)?; + Ok(self.inner.get_tx(tx_hash).await?) + } +} diff --git a/validator-api/src/coconut/deposit.rs b/validator-api/src/coconut/deposit.rs new file mode 100644 index 0000000000..7c8f2c218b --- /dev/null +++ b/validator-api/src/coconut/deposit.rs @@ -0,0 +1,441 @@ +// Copyright 2022 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use coconut_bandwidth_contract_common::events::{ + DEPOSITED_FUNDS_EVENT_TYPE, DEPOSIT_ENCRYPTION_KEY, DEPOSIT_IDENTITY_KEY, DEPOSIT_INFO, + DEPOSIT_VALUE, +}; +use coconut_interface::BlindSignRequestBody; +use credentials::coconut::bandwidth::BandwidthVoucher; +use crypto::asymmetric::encryption; +use crypto::asymmetric::identity::{self, Signature}; +use validator_client::nymd::TxResponse; + +use super::error::{CoconutError, Result}; + +pub async fn extract_encryption_key( + blind_sign_request_body: &BlindSignRequestBody, + tx: TxResponse, +) -> Result { + let blind_sign_request = blind_sign_request_body.blind_sign_request(); + let public_attributes = blind_sign_request_body.public_attributes(); + let public_attributes_plain = blind_sign_request_body.public_attributes_plain(); + + if !BandwidthVoucher::verify_against_plain(&public_attributes, public_attributes_plain) { + return Err(CoconutError::InconsistentPublicAttributes); + } + + let tx_hash_str = blind_sign_request_body.tx_hash(); + let mut message = blind_sign_request.to_bytes(); + message.extend_from_slice(tx_hash_str.as_bytes()); + + let signature = Signature::from_base58_string(blind_sign_request_body.signature())?; + + let attributes: &Vec<_> = tx + .tx_result + .events + .iter() + .find(|event| event.type_str == format!("wasm-{}", DEPOSITED_FUNDS_EVENT_TYPE)) + .ok_or(CoconutError::DepositEventNotFound)? + .attributes + .as_ref(); + + let deposit_value = attributes + .iter() + .find(|tag| tag.key.as_ref() == DEPOSIT_VALUE) + .ok_or(CoconutError::DepositValueNotFound)? + .value + .as_ref(); + let deposit_value_plain = public_attributes_plain.get(0).cloned().unwrap_or_default(); + if deposit_value != deposit_value_plain { + return Err(CoconutError::DifferentPublicAttributes( + deposit_value.to_string(), + deposit_value_plain, + )); + } + + let deposit_info = attributes + .iter() + .find(|tag| tag.key.as_ref() == DEPOSIT_INFO) + .ok_or(CoconutError::DepositInfoNotFound)? + .value + .as_ref(); + let deposit_info_plain = public_attributes_plain.get(1).cloned().unwrap_or_default(); + if deposit_info != deposit_info_plain { + return Err(CoconutError::DifferentPublicAttributes( + deposit_info.to_string(), + deposit_info_plain, + )); + } + + let verification_key = identity::PublicKey::from_base58_string( + attributes + .iter() + .find(|tag| tag.key.as_ref() == DEPOSIT_IDENTITY_KEY) + .ok_or(CoconutError::DepositVerifKeyNotFound)? + .value + .as_ref(), + )?; + + let encryption_key = encryption::PublicKey::from_base58_string( + attributes + .iter() + .find(|tag| tag.key.as_ref() == DEPOSIT_ENCRYPTION_KEY) + .ok_or(CoconutError::DepositEncrKeyNotFound)? + .value + .as_ref(), + )?; + + verification_key.verify(&message, &signature)?; + + Ok(encryption_key) +} + +#[cfg(test)] +mod test { + use super::*; + use crate::coconut::tests::tx_entry_fixture; + use config::defaults::VOUCHER_INFO; + use nymcoconut::{prepare_blind_sign, BlindSignRequest, Parameters}; + use rand_07::rngs::OsRng; + use std::str::FromStr; + use validator_client::nymd::tx::Hash; + use validator_client::nymd::{Event, Tag}; + + #[tokio::test] + async fn extract_encryption_key_test() { + let tx_hash = + Hash::from_str("6B27412050B823E58BB38447D7870BBC8CBE3C51C905BEA89D459ACCDA80A00E") + .unwrap(); + let mut tx_entry = tx_entry_fixture(&tx_hash.to_string()); + let params = Parameters::new(4).unwrap(); + let mut rng = OsRng; + let voucher = BandwidthVoucher::new( + ¶ms, + "1234".to_string(), + VOUCHER_INFO.to_string(), + tx_hash.clone(), + identity::PrivateKey::from_base58_string( + identity::KeyPair::new(&mut rng) + .private_key() + .to_base58_string(), + ) + .unwrap(), + encryption::KeyPair::new(&mut rng).private_key().clone(), + ); + let (_, blind_sign_req) = prepare_blind_sign( + ¶ms, + &voucher.get_private_attributes(), + &voucher.get_public_attributes(), + ) + .unwrap(); + let signature = "2DHbEZ6pzToGpsAXJrqJi7Wj1pAXeT18283q2YEEyNH5gTymwRozWBdja6SMAVt1dyYmUnM4ZNhsJ4wxZyGh4Z6J".to_string(); + + let req = BlindSignRequestBody::new( + &blind_sign_req, + tx_hash.to_string(), + signature.clone(), + &voucher.get_public_attributes(), + vec![ + String::from("First wrong plain"), + String::from("Second wrong plain"), + ], + 4, + ); + let err = extract_encryption_key(&req, tx_entry.clone()) + .await + .unwrap_err(); + assert_eq!( + err.to_string(), + CoconutError::InconsistentPublicAttributes.to_string() + ); + + let req = BlindSignRequestBody::new( + &blind_sign_req, + tx_hash.to_string(), + String::from("Invalid signature"), + &voucher.get_public_attributes(), + voucher.get_public_attributes_plain(), + 4, + ); + let err = extract_encryption_key(&req, tx_entry.clone()) + .await + .unwrap_err(); + assert_eq!( + err.to_string(), + CoconutError::Ed25519ParseError( + // this is really just a useless, dummy error value needed to generate the error type + // and get its string representation + crypto::asymmetric::identity::Ed25519RecoveryError::MalformedBytes( + crypto::asymmetric::identity::SignatureError::new(), + ), + ) + .to_string() + ); + + let correct_request = BlindSignRequestBody::new( + &blind_sign_req, + tx_hash.to_string(), + signature.clone(), + &voucher.get_public_attributes(), + voucher.get_public_attributes_plain(), + 4, + ); + + tx_entry.tx_result.events.push(Event { + type_str: format!("wasm-{}", DEPOSITED_FUNDS_EVENT_TYPE), + attributes: vec![], + }); + let err = extract_encryption_key(&correct_request, tx_entry.clone()) + .await + .unwrap_err(); + assert_eq!( + err.to_string(), + CoconutError::DepositValueNotFound.to_string(), + ); + + tx_entry.tx_result.events.get_mut(0).unwrap().attributes = vec![Tag { + key: DEPOSIT_VALUE.parse().unwrap(), + value: "10".parse().unwrap(), + }]; + let err = extract_encryption_key(&correct_request, tx_entry.clone()) + .await + .unwrap_err(); + assert_eq!( + err.to_string(), + CoconutError::DifferentPublicAttributes("10".to_string(), "1234".to_string()) + .to_string(), + ); + + tx_entry.tx_result.events.get_mut(0).unwrap().attributes = vec![Tag { + key: DEPOSIT_VALUE.parse().unwrap(), + value: "1234".parse().unwrap(), + }]; + let err = extract_encryption_key(&correct_request, tx_entry.clone()) + .await + .unwrap_err(); + assert_eq!( + err.to_string(), + CoconutError::DepositInfoNotFound.to_string(), + ); + + tx_entry.tx_result.events.get_mut(0).unwrap().attributes = vec![ + Tag { + key: DEPOSIT_VALUE.parse().unwrap(), + value: "1234".parse().unwrap(), + }, + Tag { + key: DEPOSIT_INFO.parse().unwrap(), + value: "bandwidth deposit info".parse().unwrap(), + }, + ]; + let err = extract_encryption_key(&correct_request, tx_entry.clone()) + .await + .unwrap_err(); + assert_eq!( + err.to_string(), + CoconutError::DifferentPublicAttributes( + "bandwidth deposit info".to_string(), + VOUCHER_INFO.to_string(), + ) + .to_string(), + ); + + tx_entry.tx_result.events.get_mut(0).unwrap().attributes = vec![ + Tag { + key: DEPOSIT_VALUE.parse().unwrap(), + value: "1234".parse().unwrap(), + }, + Tag { + key: DEPOSIT_INFO.parse().unwrap(), + value: VOUCHER_INFO.parse().unwrap(), + }, + ]; + let err = extract_encryption_key(&correct_request, tx_entry.clone()) + .await + .unwrap_err(); + assert_eq!( + err.to_string(), + CoconutError::DepositVerifKeyNotFound.to_string(), + ); + + tx_entry.tx_result.events.get_mut(0).unwrap().attributes = vec![ + Tag { + key: DEPOSIT_VALUE.parse().unwrap(), + value: "1234".parse().unwrap(), + }, + Tag { + key: DEPOSIT_INFO.parse().unwrap(), + value: VOUCHER_INFO.parse().unwrap(), + }, + Tag { + key: DEPOSIT_IDENTITY_KEY.parse().unwrap(), + value: "verification key".parse().unwrap(), + }, + ]; + let err = extract_encryption_key(&correct_request, tx_entry.clone()) + .await + .unwrap_err(); + assert_eq!( + err.to_string(), + CoconutError::Ed25519ParseError( + // this is really just a useless, dummy error value needed to generate the error type + // and get its string representation + crypto::asymmetric::identity::Ed25519RecoveryError::MalformedBytes( + crypto::asymmetric::identity::SignatureError::new(), + ), + ) + .to_string(), + ); + + tx_entry.tx_result.events.get_mut(0).unwrap().attributes = vec![ + Tag { + key: DEPOSIT_VALUE.parse().unwrap(), + value: "1234".parse().unwrap(), + }, + Tag { + key: DEPOSIT_INFO.parse().unwrap(), + value: VOUCHER_INFO.parse().unwrap(), + }, + Tag { + key: DEPOSIT_IDENTITY_KEY.parse().unwrap(), + value: "2eSxwquNJb2nZTEW5p4rbqjHfBaz9UaNhjHHiexPN4He" + .parse() + .unwrap(), + }, + ]; + let err = extract_encryption_key(&correct_request, tx_entry.clone()) + .await + .unwrap_err(); + assert_eq!( + err.to_string(), + CoconutError::DepositEncrKeyNotFound.to_string(), + ); + + tx_entry.tx_result.events.get_mut(0).unwrap().attributes = vec![ + Tag { + key: DEPOSIT_VALUE.parse().unwrap(), + value: "1234".parse().unwrap(), + }, + Tag { + key: DEPOSIT_INFO.parse().unwrap(), + value: VOUCHER_INFO.parse().unwrap(), + }, + Tag { + key: DEPOSIT_IDENTITY_KEY.parse().unwrap(), + value: "6EJGMdEq7t8Npz54uPkftGsdmj7DKntLVputAnDfVZB2" + .parse() + .unwrap(), + }, + Tag { + key: DEPOSIT_ENCRYPTION_KEY.parse().unwrap(), + value: "encryption key".parse().unwrap(), + }, + ]; + let err = extract_encryption_key(&correct_request, tx_entry.clone()) + .await + .unwrap_err(); + assert_eq!( + err.to_string(), + CoconutError::X25519ParseError( + // this is really just a useless, dummy error value needed to generate the error type + // and get its string representation + crypto::asymmetric::encryption::KeyRecoveryError::InvalidPublicKeyBytes, + ) + .to_string(), + ); + + let expected_encryption_key = "HxnTpWTkgigSTAysVKLE8pEiUULHdTT1BxFfzfJvQRi6"; + tx_entry.tx_result.events.get_mut(0).unwrap().attributes = vec![ + Tag { + key: DEPOSIT_VALUE.parse().unwrap(), + value: "1234".parse().unwrap(), + }, + Tag { + key: DEPOSIT_INFO.parse().unwrap(), + value: VOUCHER_INFO.parse().unwrap(), + }, + Tag { + key: DEPOSIT_IDENTITY_KEY.parse().unwrap(), + value: "6EJGMdEq7t8Npz54uPkftGsdmj7DKntLVputAnDfVZB2" + .parse() + .unwrap(), + }, + Tag { + key: DEPOSIT_ENCRYPTION_KEY.parse().unwrap(), + value: expected_encryption_key.parse().unwrap(), + }, + ]; + let err = extract_encryption_key(&correct_request, tx_entry.clone()) + .await + .unwrap_err(); + assert_eq!( + err.to_string(), + CoconutError::SignatureVerificationError( + crypto::asymmetric::identity::SignatureError::default(), + ) + .to_string(), + ); + + // hard-coded values, that generate a correct signature + let blind_sign_req = BlindSignRequest::from_bytes(&[ + 176, 113, 19, 237, 218, 252, 113, 20, 225, 238, 59, 88, 217, 45, 233, 178, 65, 28, 242, + 0, 222, 48, 110, 216, 26, 111, 51, 235, 61, 74, 200, 15, 130, 245, 45, 170, 155, 190, + 156, 77, 180, 142, 29, 63, 15, 224, 150, 31, 139, 24, 65, 175, 143, 153, 11, 203, 33, + 16, 152, 22, 221, 203, 99, 233, 208, 142, 161, 194, 46, 227, 177, 96, 119, 30, 175, 69, + 104, 14, 2, 191, 26, 94, 30, 165, 15, 28, 40, 176, 1, 78, 253, 79, 20, 137, 102, 74, 2, + 0, 0, 0, 0, 0, 0, 0, 131, 133, 112, 115, 53, 98, 58, 166, 240, 70, 185, 210, 203, 12, + 114, 66, 180, 38, 139, 12, 187, 45, 250, 201, 68, 102, 159, 172, 218, 124, 151, 23, + 172, 18, 216, 122, 246, 7, 185, 76, 20, 167, 123, 122, 152, 241, 175, 226, 176, 8, 170, + 70, 140, 252, 36, 130, 67, 204, 111, 116, 107, 92, 200, 77, 252, 31, 138, 18, 10, 215, + 165, 243, 95, 199, 193, 61, 200, 187, 22, 198, 109, 213, 145, 71, 171, 132, 174, 68, + 105, 248, 0, 115, 50, 55, 199, 84, 67, 16, 125, 216, 250, 154, 115, 174, 9, 206, 44, + 88, 63, 163, 124, 10, 239, 64, 158, 191, 27, 169, 177, 194, 223, 142, 202, 206, 189, + 122, 123, 91, 171, 15, 40, 192, 148, 75, 174, 24, 116, 229, 127, 170, 110, 183, 151, 2, + 118, 168, 22, 113, 87, 237, 91, 228, 249, 120, 114, 255, 53, 175, 245, 39, 2, 0, 0, 0, + 0, 0, 0, 0, 225, 45, 230, 25, 62, 202, 96, 166, 171, 241, 206, 137, 254, 51, 154, 255, + 122, 130, 107, 54, 5, 206, 207, 120, 193, 214, 64, 10, 111, 195, 86, 55, 201, 36, 10, + 18, 154, 158, 183, 87, 185, 59, 228, 89, 134, 193, 217, 188, 64, 164, 249, 21, 248, 20, + 207, 58, 31, 10, 19, 176, 246, 150, 45, 48, 2, 0, 0, 0, 0, 0, 0, 0, 173, 60, 65, 209, + 100, 114, 138, 186, 158, 150, 109, 230, 111, 86, 101, 72, 194, 237, 173, 195, 139, 175, + 238, 25, 169, 18, 188, 75, 77, 54, 111, 20, 115, 235, 195, 2, 123, 133, 164, 81, 15, + 45, 11, 84, 139, 38, 8, 224, 197, 181, 95, 147, 49, 77, 193, 207, 52, 141, 195, 195, + 66, 137, 17, 32, + ]) + .unwrap(); + let correct_request = BlindSignRequestBody::new( + &blind_sign_req, + "7C41AF8266D91DE55E1C8F4712E6A952A165ED3D8C27C7B00428CBD0DE00A52B".to_string(), + "gSFgpma5GAVMcsmZwKieqGNHNd3dPzcfa8eT2Qn2LoBccSeyiJdphREbNrkuh5XWxMe2hUsranaYzLro48L9Qhd".to_string(), + &voucher.get_public_attributes(), + voucher.get_public_attributes_plain(), + 4, + ); + tx_entry.tx_result.events.get_mut(0).unwrap().attributes = vec![ + Tag { + key: DEPOSIT_VALUE.parse().unwrap(), + value: "1234".parse().unwrap(), + }, + Tag { + key: DEPOSIT_INFO.parse().unwrap(), + value: VOUCHER_INFO.parse().unwrap(), + }, + Tag { + key: DEPOSIT_IDENTITY_KEY.parse().unwrap(), + value: "64auwDkWan7R8yH1Mwe9dS4qXgrDBCUNDg3Q4KFnd2P5" + .parse() + .unwrap(), + }, + Tag { + key: DEPOSIT_ENCRYPTION_KEY.parse().unwrap(), + value: "HxnTpWTkgigSTAysVKLE8pEiUULHdTT1BxFfzfJvQRi6" + .parse() + .unwrap(), + }, + ]; + let encryption_key = extract_encryption_key(&correct_request, tx_entry.clone()) + .await + .unwrap(); + assert_eq!(encryption_key.to_base58_string(), expected_encryption_key); + } +} diff --git a/validator-api/src/coconut/error.rs b/validator-api/src/coconut/error.rs new file mode 100644 index 0000000000..fb2ff73419 --- /dev/null +++ b/validator-api/src/coconut/error.rs @@ -0,0 +1,79 @@ +// Copyright 2022 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use rocket::http::{ContentType, Status}; +use rocket::response::Responder; +use rocket::{response, Request, Response}; +use std::io::Cursor; +use thiserror::Error; + +use crypto::asymmetric::{ + encryption::KeyRecoveryError, + identity::{Ed25519RecoveryError, SignatureError}, +}; +use validator_client::nymd::error::NymdError; + +use crate::node_status_api::models::ValidatorApiStorageError; + +pub type Result = std::result::Result; + +#[derive(Debug, Error)] +pub enum CoconutError { + #[error("Could not parse Ed25519 data")] + Ed25519ParseError(#[from] Ed25519RecoveryError), + + #[error("Could not parse X25519 data")] + X25519ParseError(#[from] KeyRecoveryError), + + #[error("Could not parse tx hash in request body")] + TxHashParseError, + + #[error("Nymd error - {0}")] + NymdError(#[from] NymdError), + + #[error("Could not find a deposit event in the transaction provided")] + DepositEventNotFound, + + #[error("Could not find the deposit value in the event")] + DepositValueNotFound, + + #[error("Could not find the deposit info in the event")] + DepositInfoNotFound, + + #[error("Could not find the verification key in the event")] + DepositVerifKeyNotFound, + + #[error("Could not find the encryption key in the event")] + DepositEncrKeyNotFound, + + #[error("Signature didn't verify correctly")] + SignatureVerificationError(#[from] SignatureError), + + #[error("Inconsistent public attributes")] + InconsistentPublicAttributes, + + #[error( + "Public attributes in request differ from the ones in deposit - Expected {0}, got {1}" + )] + DifferentPublicAttributes(String, String), + + #[error("No signature found")] + NoSignature, + + #[error("Error in coconut interface - {0}")] + CoconutInterfaceError(#[from] coconut_interface::error::CoconutInterfaceError), + + #[error("Storage error - {0}")] + StorageError(#[from] ValidatorApiStorageError), +} + +impl<'r, 'o: 'r> Responder<'r, 'o> for CoconutError { + fn respond_to(self, _: &'r Request<'_>) -> response::Result<'o> { + let err_msg = self.to_string(); + Response::build() + .header(ContentType::Plain) + .sized_body(err_msg.len(), Cursor::new(err_msg)) + .status(Status::BadRequest) + .ok() + } +} diff --git a/validator-api/src/coconut/mod.rs b/validator-api/src/coconut/mod.rs index 780c6e63f8..0478a19977 100644 --- a/validator-api/src/coconut/mod.rs +++ b/validator-api/src/coconut/mod.rs @@ -1,15 +1,115 @@ // Copyright 2021 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 +pub(crate) mod client; +mod deposit; +mod error; +#[cfg(test)] +mod tests; + +use crate::coconut::client::Client as LocalClient; +use crate::coconut::deposit::extract_encryption_key; +use crate::coconut::error::{CoconutError, Result}; +use crate::ValidatorApiStorage; + use coconut_interface::{ Attribute, BlindSignRequest, BlindSignRequestBody, BlindedSignature, BlindedSignatureResponse, KeyPair, Parameters, VerificationKeyResponse, }; use config::defaults::VALIDATOR_API_VERSION; +use credentials::coconut::params::{ + ValidatorApiCredentialEncryptionAlgorithm, ValidatorApiCredentialHkdfAlgorithm, +}; +use crypto::asymmetric::encryption; +use crypto::shared_key::new_ephemeral_shared_key; +use crypto::symmetric::stream_cipher; + use getset::{CopyGetters, Getters}; +use rand_07::rngs::OsRng; use rocket::fairing::AdHoc; use rocket::serde::json::Json; -use rocket::State; +use rocket::State as RocketState; +use std::sync::Arc; +use tokio::sync::{Mutex, RwLock}; +use validator_client::validator_api::routes::{BANDWIDTH, COCONUT_ROUTES}; + +pub struct State { + client: Arc>, + key_pair: KeyPair, + storage: ValidatorApiStorage, + rng: Arc>, +} + +impl State { + pub(crate) fn new(client: C, key_pair: KeyPair, storage: ValidatorApiStorage) -> Self + where + C: LocalClient + Send + Sync + 'static, + { + let client = Arc::new(RwLock::new(client)); + let rng = Arc::new(Mutex::new(OsRng)); + Self { + client, + key_pair, + storage, + rng, + } + } + + pub async fn signed_before(&self, tx_hash: &str) -> Result> { + let ret = self.storage.get_blinded_signature_response(tx_hash).await?; + if let Some(blinded_signature_reponse) = ret { + Ok(Some(BlindedSignatureResponse::from_base58_string( + &blinded_signature_reponse, + )?)) + } else { + Ok(None) + } + } + + pub async fn encrypt_and_store( + &self, + tx_hash: &str, + remote_key: &encryption::PublicKey, + signature: &BlindedSignature, + ) -> Result { + let (keypair, shared_key) = { + let mut rng = *self.rng.lock().await; + new_ephemeral_shared_key::< + ValidatorApiCredentialEncryptionAlgorithm, + ValidatorApiCredentialHkdfAlgorithm, + _, + >(&mut rng, remote_key) + }; + + let chunk_data = signature.to_bytes(); + + let zero_iv = stream_cipher::zero_iv::(); + let encrypted_data = stream_cipher::encrypt::( + &shared_key, + &zero_iv, + &chunk_data, + ); + + let response = + BlindedSignatureResponse::new(encrypted_data, keypair.public_key().to_bytes()); + + // Atomically insert data, only if there is no signature stored in the meantime + // This prevents race conditions on storing two signatures for the same deposit transaction + if self + .storage + .insert_blinded_signature_response(tx_hash, &response.to_base58_string()) + .await + .is_err() + { + Ok(self + .signed_before(tx_hash) + .await? + .expect("The signature was expected to be there")) + } else { + Ok(response) + } + } +} #[derive(Getters, CopyGetters, Debug)] pub(crate) struct InternalSignRequest { @@ -35,12 +135,23 @@ impl InternalSignRequest { } } - pub fn stage(key_pair: KeyPair) -> AdHoc { + pub fn stage(client: C, key_pair: KeyPair, storage: ValidatorApiStorage) -> AdHoc + where + C: LocalClient + Send + Sync + 'static, + { + let state = State::new(client, key_pair, storage); AdHoc::on_ignite("Internal Sign Request Stage", |rocket| async { - rocket.manage(key_pair).mount( + rocket.manage(state).mount( // this format! is so ugly... - format!("/{}", VALIDATOR_API_VERSION), - routes![post_blind_sign, get_verification_key], + format!( + "/{}/{}/{}", + VALIDATOR_API_VERSION, COCONUT_ROUTES, BANDWIDTH + ), + routes![ + post_blind_sign, + get_verification_key, + post_partial_bandwidth_credential + ], ) }) } @@ -61,19 +172,57 @@ fn blind_sign(request: InternalSignRequest, key_pair: &KeyPair) -> BlindedSignat // Until we have serialization and deserialization traits we'll be using a crutch pub async fn post_blind_sign( blind_sign_request_body: Json, - key_pair: &State, -) -> Json { + state: &RocketState, +) -> Result> { debug!("{:?}", blind_sign_request_body); + if let Some(response) = state + .signed_before(blind_sign_request_body.tx_hash()) + .await? + { + return Ok(Json(response)); + } + let tx = state + .client + .read() + .await + .get_tx(blind_sign_request_body.tx_hash()) + .await?; + let encryption_key = extract_encryption_key(&blind_sign_request_body, tx).await?; let internal_request = InternalSignRequest::new( *blind_sign_request_body.total_params(), blind_sign_request_body.public_attributes(), blind_sign_request_body.blind_sign_request().clone(), ); - let blinded_signature = blind_sign(internal_request, key_pair); - Json(BlindedSignatureResponse::new(blinded_signature)) + let blinded_signature = blind_sign(internal_request, &state.key_pair); + + let response = state + .encrypt_and_store( + blind_sign_request_body.tx_hash(), + &encryption_key, + &blinded_signature, + ) + .await?; + + Ok(Json(response)) +} + +#[post("/partial-bandwidth-credential", data = "")] +pub async fn post_partial_bandwidth_credential( + tx_hash: Json, + state: &RocketState, +) -> Result> { + let v = state + .signed_before(&tx_hash) + .await? + .ok_or(CoconutError::NoSignature)?; + Ok(Json(v)) } #[get("/verification-key")] -pub async fn get_verification_key(key_pair: &State) -> Json { - Json(VerificationKeyResponse::new(key_pair.verification_key())) +pub async fn get_verification_key( + state: &RocketState, +) -> Result> { + Ok(Json(VerificationKeyResponse::new( + state.key_pair.verification_key(), + ))) } diff --git a/validator-api/src/coconut/tests.rs b/validator-api/src/coconut/tests.rs new file mode 100644 index 0000000000..56c95572bc --- /dev/null +++ b/validator-api/src/coconut/tests.rs @@ -0,0 +1,510 @@ +// Copyright 2022 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use super::InternalSignRequest; +use crate::coconut::error::{CoconutError, Result}; +use coconut_bandwidth_contract_common::events::{ + DEPOSITED_FUNDS_EVENT_TYPE, DEPOSIT_ENCRYPTION_KEY, DEPOSIT_IDENTITY_KEY, DEPOSIT_INFO, + DEPOSIT_VALUE, +}; +use coconut_interface::{BlindSignRequestBody, BlindedSignatureResponse, VerificationKeyResponse}; +use config::defaults::VOUCHER_INFO; +use credentials::coconut::bandwidth::BandwidthVoucher; +use credentials::coconut::params::{ + ValidatorApiCredentialEncryptionAlgorithm, ValidatorApiCredentialHkdfAlgorithm, +}; +use crypto::shared_key::recompute_shared_key; +use crypto::symmetric::stream_cipher; +use nymcoconut::{ + prepare_blind_sign, ttp_keygen, Base58, BlindSignRequest, BlindedSignature, KeyPair, Parameters, +}; +use validator_client::nymd::{tx::Hash, DeliverTx, Event, Tag, TxResponse}; +use validator_client::validator_api::routes::{ + API_VERSION, BANDWIDTH, COCONUT_BLIND_SIGN, COCONUT_PARTIAL_BANDWIDTH_CREDENTIAL, + COCONUT_ROUTES, COCONUT_VERIFICATION_KEY, +}; + +use crate::coconut::State; +use crate::ValidatorApiStorage; +use async_trait::async_trait; +use crypto::asymmetric::{encryption, identity}; +use rand_07::rngs::OsRng; +use rocket::http::Status; +use rocket::local::asynchronous::Client; +use std::collections::HashMap; +use std::str::FromStr; +use std::sync::{Arc, RwLock}; + +struct DummyClient { + db: Arc>>, +} + +impl DummyClient { + pub fn new(db: &Arc>>) -> Self { + let db = Arc::clone(db); + Self { db } + } +} + +#[async_trait] +impl super::client::Client for DummyClient { + async fn get_tx(&self, tx_hash: &str) -> Result { + self.db + .read() + .unwrap() + .get(tx_hash) + .cloned() + .ok_or(CoconutError::TxHashParseError) + } +} + +pub fn tx_entry_fixture(tx_hash: &str) -> TxResponse { + TxResponse { + hash: Hash::from_str(tx_hash).unwrap(), + height: Default::default(), + index: 0, + tx_result: DeliverTx { + code: Default::default(), + data: Default::default(), + log: Default::default(), + info: Default::default(), + gas_wanted: Default::default(), + gas_used: Default::default(), + events: vec![], + codespace: Default::default(), + }, + tx: vec![].into(), + proof: None, + } +} + +async fn check_signer_verif_key(key_pair: KeyPair) { + let verification_key = key_pair.verification_key(); + + let mut db_dir = std::env::temp_dir(); + db_dir.push(&verification_key.to_bs58()[..8]); + let storage = ValidatorApiStorage::init(db_dir).await.unwrap(); + let nymd_db = Arc::new(RwLock::new(HashMap::new())); + let nymd_client = DummyClient::new(&nymd_db); + + let rocket = rocket::build().attach(InternalSignRequest::stage(nymd_client, key_pair, storage)); + + let client = Client::tracked(rocket) + .await + .expect("valid rocket instance"); + + let response = client + .get(format!( + "/{}/{}/{}/{}", + API_VERSION, COCONUT_ROUTES, BANDWIDTH, COCONUT_VERIFICATION_KEY + )) + .dispatch() + .await; + assert_eq!(response.status(), Status::Ok); + + // This is a more direct way, but there's a bug which makes it hang https://github.com/SergioBenitez/Rocket/issues/1893 + // assert!(response + // .into_json::() + // .await + // .is_some()); + let verification_key_response = + serde_json::from_str::(&response.into_string().await.unwrap()) + .unwrap(); + assert_eq!(verification_key_response.key, verification_key); +} + +#[tokio::test] +async fn multiple_verification_key() { + let params = Parameters::new(4).unwrap(); + let num_authorities = 4; + + let key_pairs = ttp_keygen(¶ms, num_authorities, num_authorities).unwrap(); + for key_pair in key_pairs.into_iter() { + check_signer_verif_key(key_pair).await; + } +} + +#[tokio::test] +async fn signed_before() { + let tx_hash = + Hash::from_str("6B27412050B823E58BB38447D7870BBC8CBE3C51C905BEA89D459ACCDA80A00E").unwrap(); + let tx_entry = tx_entry_fixture(&tx_hash.to_string()); + let signature = String::from( + "2DHbEZ6pzToGpsAXJrqJi7Wj1pAXeT18283q2YEEyNH5gTymwRozWBdja6SMAVt1dyYmUnM4ZNhsJ4wxZyGh4Z6J", + ); + + let params = Parameters::new(4).unwrap(); + let mut rng = OsRng; + let voucher = BandwidthVoucher::new( + ¶ms, + "1234".to_string(), + VOUCHER_INFO.to_string(), + tx_hash.clone(), + identity::PrivateKey::from_base58_string( + identity::KeyPair::new(&mut rng) + .private_key() + .to_base58_string(), + ) + .unwrap(), + encryption::KeyPair::new(&mut rng).private_key().clone(), + ); + let (_, blind_sign_req) = prepare_blind_sign( + ¶ms, + &voucher.get_private_attributes(), + &voucher.get_public_attributes(), + ) + .unwrap(); + + let key_pair = ttp_keygen(¶ms, 1, 1).unwrap().remove(0); + let mut db_dir = std::env::temp_dir(); + db_dir.push(&key_pair.verification_key().to_bs58()[..8]); + let storage = ValidatorApiStorage::init(db_dir).await.unwrap(); + let nymd_db = Arc::new(RwLock::new(HashMap::new())); + nymd_db + .write() + .unwrap() + .insert(tx_hash.to_string(), tx_entry.clone()); + let nymd_client = DummyClient::new(&nymd_db); + + let rocket = rocket::build().attach(InternalSignRequest::stage( + nymd_client, + key_pair, + storage.clone(), + )); + let client = Client::tracked(rocket) + .await + .expect("valid rocket instance"); + + let request_body = BlindSignRequestBody::new( + &blind_sign_req, + tx_hash.to_string(), + signature.clone(), + &voucher.get_public_attributes(), + voucher.get_public_attributes_plain(), + 4, + ); + + let encrypted_signature = vec![1, 2, 3, 4]; + let remote_key = [42; 32]; + let expected_response = BlindedSignatureResponse::new(encrypted_signature, remote_key); + storage + .insert_blinded_signature_response( + &tx_hash.to_string(), + &expected_response.to_base58_string(), + ) + .await + .unwrap(); + + let response = client + .post(format!( + "/{}/{}/{}/{}", + API_VERSION, COCONUT_ROUTES, BANDWIDTH, COCONUT_BLIND_SIGN + )) + .json(&request_body) + .dispatch() + .await; + assert_eq!(response.status(), Status::Ok); + + // This is a more direct way, but there's a bug which makes it hang https://github.com/SergioBenitez/Rocket/issues/1893 + // let blinded_signature_response = response + // .into_json::() + // .await + // .unwrap(); + let blinded_signature_response = + serde_json::from_str::(&response.into_string().await.unwrap()) + .unwrap(); + assert_eq!( + blinded_signature_response.to_bytes(), + expected_response.to_bytes() + ); +} + +#[tokio::test] +async fn state_functions() { + let nymd_db = Arc::new(RwLock::new(HashMap::new())); + let nymd_client = DummyClient::new(&nymd_db); + let params = Parameters::new(4).unwrap(); + let key_pair = ttp_keygen(¶ms, 1, 1).unwrap().remove(0); + let mut db_dir = std::env::temp_dir(); + db_dir.push(&key_pair.verification_key().to_bs58()[..8]); + let storage = ValidatorApiStorage::init(db_dir).await.unwrap(); + let state = State::new(nymd_client, key_pair, storage.clone()); + + let tx_hash = String::from("6B27412050B823E58BB38447D7870BBC8CBE3C51C905BEA89D459ACCDA80A00E"); + assert!(state.signed_before(&tx_hash).await.unwrap().is_none()); + + let encrypted_signature = vec![1, 2, 3, 4]; + let remote_key = [42; 32]; + let expected_response = BlindedSignatureResponse::new(encrypted_signature, remote_key); + storage + .insert_blinded_signature_response(&tx_hash, &expected_response.to_base58_string()) + .await + .unwrap(); + assert_eq!( + state + .signed_before(&tx_hash) + .await + .unwrap() + .unwrap() + .to_bytes(), + expected_response.to_bytes() + ); + + let encryption_keypair = crypto::asymmetric::encryption::KeyPair::new(&mut OsRng); + let blinded_signature = BlindedSignature::from_bytes(&[ + 183, 217, 166, 113, 40, 123, 74, 25, 72, 31, 136, 19, 125, 95, 217, 228, 96, 113, 25, 240, + 12, 102, 125, 11, 174, 20, 216, 82, 192, 71, 27, 194, 48, 20, 17, 95, 243, 179, 82, 21, 57, + 143, 101, 19, 22, 186, 147, 13, 147, 238, 39, 119, 15, 36, 251, 131, 250, 38, 185, 113, + 187, 40, 227, 107, 134, 190, 123, 183, 126, 176, 226, 173, 147, 137, 17, 175, 13, 115, 78, + 222, 119, 93, 146, 116, 229, 0, 152, 51, 232, 2, 102, 204, 147, 202, 254, 243, + ]) + .unwrap(); + // Check that the new payload is not stored if there was already something signed for tx_hash + assert_eq!( + state + .encrypt_and_store( + &tx_hash, + encryption_keypair.public_key(), + &blinded_signature, + ) + .await + .unwrap() + .to_bytes(), + expected_response.to_bytes() + ); + + // And use a new hash to store a new signature + let tx_hash = String::from("97D64C38D6601B1F0FD3A82E20D252685CB7A210AFB0261018590659AB82B0BF"); + let response = state + .encrypt_and_store( + &tx_hash, + encryption_keypair.public_key(), + &blinded_signature, + ) + .await + .unwrap(); + let remote_key = + crypto::asymmetric::encryption::PublicKey::from_bytes(&response.remote_key).unwrap(); + + let encryption_key = recompute_shared_key::< + ValidatorApiCredentialEncryptionAlgorithm, + ValidatorApiCredentialHkdfAlgorithm, + >(&remote_key, encryption_keypair.private_key()); + let zero_iv = stream_cipher::zero_iv::(); + let blinded_signature_bytes = stream_cipher::decrypt::( + &encryption_key, + &zero_iv, + &response.encrypted_signature, + ); + + let received_blinded_signature = + BlindedSignature::from_bytes(&blinded_signature_bytes).unwrap(); + assert_eq!( + blinded_signature.to_bytes(), + received_blinded_signature.to_bytes() + ); + + // Check that the same value for tx_hash is returned + + let other_signature = BlindedSignature::from_bytes(&[ + 183, 217, 166, 113, 40, 123, 74, 25, 72, 31, 136, 19, 125, 95, 217, 228, 96, 113, 25, 240, + 12, 102, 125, 11, 174, 20, 216, 82, 192, 71, 27, 194, 48, 20, 17, 95, 243, 179, 82, 21, 57, + 143, 101, 19, 22, 186, 147, 13, 131, 236, 38, 138, 192, 235, 169, 142, 176, 118, 153, 238, + 141, 91, 94, 139, 168, 214, 17, 250, 96, 206, 139, 89, 139, 87, 31, 8, 106, 171, 8, 140, + 201, 158, 18, 152, 24, 98, 153, 170, 141, 35, 190, 200, 19, 148, 71, 197, + ]) + .unwrap(); + assert_eq!( + state + .encrypt_and_store(&tx_hash, encryption_keypair.public_key(), &other_signature,) + .await + .unwrap() + .to_bytes(), + response.to_bytes() + ); +} + +#[tokio::test] +async fn blind_sign_correct() { + let tx_hash = + Hash::from_str("7C41AF8266D91DE55E1C8F4712E6A952A165ED3D8C27C7B00428CBD0DE00A52B").unwrap(); + + let params = Parameters::new(4).unwrap(); + let mut rng = OsRng; + let voucher = BandwidthVoucher::new( + ¶ms, + "1234".to_string(), + VOUCHER_INFO.to_string(), + tx_hash.clone(), + identity::PrivateKey::from_base58_string( + identity::KeyPair::new(&mut rng) + .private_key() + .to_base58_string(), + ) + .unwrap(), + encryption::KeyPair::new(&mut rng).private_key().clone(), + ); + + let key_pair = ttp_keygen(¶ms, 1, 1).unwrap().remove(0); + let mut db_dir = std::env::temp_dir(); + db_dir.push(&key_pair.verification_key().to_bs58()[..8]); + let storage = ValidatorApiStorage::init(db_dir).await.unwrap(); + let nymd_db = Arc::new(RwLock::new(HashMap::new())); + + let mut tx_entry = tx_entry_fixture(&tx_hash.to_string()); + tx_entry.tx_result.events.push(Event { + type_str: format!("wasm-{}", DEPOSITED_FUNDS_EVENT_TYPE), + attributes: vec![], + }); + tx_entry.tx_result.events.get_mut(0).unwrap().attributes = vec![ + Tag { + key: DEPOSIT_VALUE.parse().unwrap(), + value: "1234".parse().unwrap(), + }, + Tag { + key: DEPOSIT_INFO.parse().unwrap(), + value: VOUCHER_INFO.parse().unwrap(), + }, + Tag { + key: DEPOSIT_IDENTITY_KEY.parse().unwrap(), + value: "64auwDkWan7R8yH1Mwe9dS4qXgrDBCUNDg3Q4KFnd2P5" + .parse() + .unwrap(), + }, + Tag { + key: DEPOSIT_ENCRYPTION_KEY.parse().unwrap(), + value: "HxnTpWTkgigSTAysVKLE8pEiUULHdTT1BxFfzfJvQRi6" + .parse() + .unwrap(), + }, + ]; + nymd_db + .write() + .unwrap() + .insert(tx_hash.to_string(), tx_entry.clone()); + let nymd_client = DummyClient::new(&nymd_db); + + let rocket = rocket::build().attach(InternalSignRequest::stage( + nymd_client, + key_pair, + storage.clone(), + )); + let client = Client::tracked(rocket) + .await + .expect("valid rocket instance"); + + // hard-coded values, that generate a correct signature + let blind_sign_req = BlindSignRequest::from_bytes(&[ + 176, 113, 19, 237, 218, 252, 113, 20, 225, 238, 59, 88, 217, 45, 233, 178, 65, 28, 242, 0, + 222, 48, 110, 216, 26, 111, 51, 235, 61, 74, 200, 15, 130, 245, 45, 170, 155, 190, 156, 77, + 180, 142, 29, 63, 15, 224, 150, 31, 139, 24, 65, 175, 143, 153, 11, 203, 33, 16, 152, 22, + 221, 203, 99, 233, 208, 142, 161, 194, 46, 227, 177, 96, 119, 30, 175, 69, 104, 14, 2, 191, + 26, 94, 30, 165, 15, 28, 40, 176, 1, 78, 253, 79, 20, 137, 102, 74, 2, 0, 0, 0, 0, 0, 0, 0, + 131, 133, 112, 115, 53, 98, 58, 166, 240, 70, 185, 210, 203, 12, 114, 66, 180, 38, 139, 12, + 187, 45, 250, 201, 68, 102, 159, 172, 218, 124, 151, 23, 172, 18, 216, 122, 246, 7, 185, + 76, 20, 167, 123, 122, 152, 241, 175, 226, 176, 8, 170, 70, 140, 252, 36, 130, 67, 204, + 111, 116, 107, 92, 200, 77, 252, 31, 138, 18, 10, 215, 165, 243, 95, 199, 193, 61, 200, + 187, 22, 198, 109, 213, 145, 71, 171, 132, 174, 68, 105, 248, 0, 115, 50, 55, 199, 84, 67, + 16, 125, 216, 250, 154, 115, 174, 9, 206, 44, 88, 63, 163, 124, 10, 239, 64, 158, 191, 27, + 169, 177, 194, 223, 142, 202, 206, 189, 122, 123, 91, 171, 15, 40, 192, 148, 75, 174, 24, + 116, 229, 127, 170, 110, 183, 151, 2, 118, 168, 22, 113, 87, 237, 91, 228, 249, 120, 114, + 255, 53, 175, 245, 39, 2, 0, 0, 0, 0, 0, 0, 0, 225, 45, 230, 25, 62, 202, 96, 166, 171, + 241, 206, 137, 254, 51, 154, 255, 122, 130, 107, 54, 5, 206, 207, 120, 193, 214, 64, 10, + 111, 195, 86, 55, 201, 36, 10, 18, 154, 158, 183, 87, 185, 59, 228, 89, 134, 193, 217, 188, + 64, 164, 249, 21, 248, 20, 207, 58, 31, 10, 19, 176, 246, 150, 45, 48, 2, 0, 0, 0, 0, 0, 0, + 0, 173, 60, 65, 209, 100, 114, 138, 186, 158, 150, 109, 230, 111, 86, 101, 72, 194, 237, + 173, 195, 139, 175, 238, 25, 169, 18, 188, 75, 77, 54, 111, 20, 115, 235, 195, 2, 123, 133, + 164, 81, 15, 45, 11, 84, 139, 38, 8, 224, 197, 181, 95, 147, 49, 77, 193, 207, 52, 141, + 195, 195, 66, 137, 17, 32, + ]) + .unwrap(); + let request_body = BlindSignRequestBody::new( + &blind_sign_req, + tx_hash.to_string(), + "gSFgpma5GAVMcsmZwKieqGNHNd3dPzcfa8eT2Qn2LoBccSeyiJdphREbNrkuh5XWxMe2hUsranaYzLro48L9Qhd" + .to_string(), + &voucher.get_public_attributes(), + voucher.get_public_attributes_plain(), + 4, + ); + + let response = client + .post(format!( + "/{}/{}/{}/{}", + API_VERSION, COCONUT_ROUTES, BANDWIDTH, COCONUT_BLIND_SIGN + )) + .json(&request_body) + .dispatch() + .await; + assert_eq!(response.status(), Status::Ok); + // This is a more direct way, but there's a bug which makes it hang https://github.com/SergioBenitez/Rocket/issues/1893 + // assert!(response.into_json::().is_some()); + let blinded_signature_response = + serde_json::from_str::(&response.into_string().await.unwrap()); + assert!(blinded_signature_response.is_ok()); +} + +#[tokio::test] +async fn signature_test() { + let tx_hash = String::from("7C41AF8266D91DE55E1C8F4712E6A952A165ED3D8C27C7B00428CBD0DE00A52B"); + let params = Parameters::new(4).unwrap(); + + let key_pair = ttp_keygen(¶ms, 1, 1).unwrap().remove(0); + let mut db_dir = std::env::temp_dir(); + db_dir.push(&key_pair.verification_key().to_bs58()[..8]); + let storage = ValidatorApiStorage::init(db_dir).await.unwrap(); + let nymd_db = Arc::new(RwLock::new(HashMap::new())); + let nymd_client = DummyClient::new(&nymd_db); + + let rocket = rocket::build().attach(InternalSignRequest::stage( + nymd_client, + key_pair, + storage.clone(), + )); + let client = Client::tracked(rocket) + .await + .expect("valid rocket instance"); + + let response = client + .post(format!( + "/{}/{}/{}/{}", + API_VERSION, COCONUT_ROUTES, BANDWIDTH, COCONUT_PARTIAL_BANDWIDTH_CREDENTIAL + )) + .json(&tx_hash) + .dispatch() + .await; + assert_eq!(response.status(), Status::BadRequest); + assert_eq!( + response.into_string().await.unwrap(), + CoconutError::NoSignature.to_string() + ); + + let encrypted_signature = vec![1, 2, 3, 4]; + let remote_key = [42; 32]; + let expected_response = BlindedSignatureResponse::new(encrypted_signature, remote_key); + storage + .insert_blinded_signature_response(&tx_hash, &expected_response.to_base58_string()) + .await + .unwrap(); + let response = client + .post(format!( + "/{}/{}/{}/{}", + API_VERSION, COCONUT_ROUTES, BANDWIDTH, COCONUT_PARTIAL_BANDWIDTH_CREDENTIAL + )) + .json(&tx_hash) + .dispatch() + .await; + assert_eq!(response.status(), Status::Ok); + // This is a more direct way, but there's a bug which makes it hang https://github.com/SergioBenitez/Rocket/issues/1893 + // let blinded_signature_response = response + // .into_json::() + // .await + // .unwrap(); + let blinded_signature_response = + serde_json::from_str::(&response.into_string().await.unwrap()) + .unwrap(); + assert_eq!( + blinded_signature_response.to_bytes(), + expected_response.to_bytes() + ); +} diff --git a/validator-api/src/config/mod.rs b/validator-api/src/config/mod.rs index 567aba8858..ab8debc22c 100644 --- a/validator-api/src/config/mod.rs +++ b/validator-api/src/config/mod.rs @@ -14,7 +14,7 @@ use coconut_interface::{Base58, KeyPair}; mod template; -const DEFAULT_LOCAL_VALIDATOR: &str = "http://localhost:26657"; +pub const DEFAULT_LOCAL_VALIDATOR: &str = "http://localhost:26657"; const DEFAULT_GATEWAY_SENDING_RATE: usize = 200; const DEFAULT_MAX_CONCURRENT_GATEWAY_CLIENTS: usize = 50; diff --git a/validator-api/src/main.rs b/validator-api/src/main.rs index 037fc3911e..8c9a7ab799 100644 --- a/validator-api/src/main.rs +++ b/validator-api/src/main.rs @@ -29,7 +29,7 @@ use url::Url; use crate::rewarded_set_updater::RewardedSetUpdater; #[cfg(feature = "coconut")] -use coconut::InternalSignRequest; +use coconut::{client::QueryClient, InternalSignRequest}; pub(crate) mod config; pub(crate) mod contract_cache; @@ -54,6 +54,9 @@ const TESTNET_MODE_ARG_NAME: &str = "testnet-mode"; #[cfg(feature = "coconut")] const KEYPAIR_ARG: &str = "keypair"; +#[cfg(feature = "coconut")] +const SIGNED_DEPOSITS_ARG: &str = "signed-deposits"; + #[cfg(feature = "coconut")] const COCONUT_ONLY_FLAG: &str = "coconut-only"; @@ -178,6 +181,11 @@ fn parse_args<'a>() -> ArgMatches<'a> { .help("Path to the secret key file") .takes_value(true) .long(KEYPAIR_ARG), + ).arg( + Arg::with_name(SIGNED_DEPOSITS_ARG) + .help("Path to the directory used to store the already signed deposit transactions. This prevents the validator for double signing for the same deposit") + .takes_value(true) + .long(SIGNED_DEPOSITS_ARG), ).arg( Arg::with_name(COCONUT_ONLY_FLAG) .help("Flag to indicate whether validator api should only be used for credential issuance with no blockchain connection") @@ -373,15 +381,25 @@ async fn setup_rocket(config: &Config, liftoff_notify: Arc) -> Result) -> Result<()> { // this simplifies everything - we just want to run coconut things return rocket::build() .attach(setup_cors()?) - .attach(InternalSignRequest::stage(config.keypair())) + .attach(InternalSignRequest::stage( + QueryClient::new()?, + config.keypair(), + ValidatorApiStorage::init(config.get_node_status_api_database_path()).await?, + )) .launch() .await .map_err(|err| err.into()); diff --git a/validator-api/src/node_status_api/models.rs b/validator-api/src/node_status_api/models.rs index bf2cbb9202..27e348b229 100644 --- a/validator-api/src/node_status_api/models.rs +++ b/validator-api/src/node_status_api/models.rs @@ -231,7 +231,7 @@ impl<'r, 'o: 'r> Responder<'r, 'o> for ErrorResponse { } } -#[derive(Debug)] +#[derive(Debug, thiserror::Error)] pub enum ValidatorApiStorageError { MixnodeReportNotFound(String), GatewayReportNotFound(String), diff --git a/validator-api/src/storage/manager.rs b/validator-api/src/storage/manager.rs index cf80dd7d18..5f08b98ccd 100644 --- a/validator-api/src/storage/manager.rs +++ b/validator-api/src/storage/manager.rs @@ -769,4 +769,47 @@ impl StorageManager { Ok(active_day_statuses) } + + /// Creates new encrypted blinded signature response entry for a given deposit tx hash. + /// + /// # Arguments + /// + /// * `tx_hash`: hash of the deposit transaction. + /// * `blinded_signature_response`: the encrypted blinded signature response. + #[cfg(feature = "coconut")] + pub(super) async fn insert_blinded_signature_response( + &self, + tx_hash: &str, + blinded_signature_response: &str, + ) -> Result<(), sqlx::Error> { + sqlx::query!( + "INSERT INTO signed_deposit(tx_hash, blinded_signature_response) VALUES (?, ?)", + tx_hash, + blinded_signature_response + ) + .execute(&self.connection_pool) + .await?; + Ok(()) + } + + /// Tries to obtain encrypted blinded signature response for a given transaction hash. + /// + /// # Arguments + /// + /// * `tx_hash`: transaction hash of the deposit. + #[cfg(feature = "coconut")] + pub(super) async fn get_blinded_signature_response( + &self, + tx_hash: &str, + ) -> Result, sqlx::Error> { + let blinded_signature_response = sqlx::query!( + "SELECT blinded_signature_response FROM signed_deposit WHERE tx_hash = ?", + tx_hash + ) + .fetch_optional(&self.connection_pool) + .await? + .map(|row| row.blinded_signature_response); + + Ok(blinded_signature_response) + } } diff --git a/validator-api/src/storage/mod.rs b/validator-api/src/storage/mod.rs index 4a17b172af..bda0d617ff 100644 --- a/validator-api/src/storage/mod.rs +++ b/validator-api/src/storage/mod.rs @@ -10,8 +10,7 @@ use crate::node_status_api::models::{ use crate::node_status_api::{ONE_DAY, ONE_HOUR}; use crate::storage::manager::StorageManager; use crate::storage::models::{NodeStatus, RewardingReport, TestingRoute}; -use rocket::fairing::{self, AdHoc}; -use rocket::{Build, Rocket}; +use rocket::fairing::AdHoc; use sqlx::ConnectOptions; use std::path::PathBuf; use time::OffsetDateTime; @@ -26,7 +25,7 @@ pub(crate) struct ValidatorApiStorage { } impl ValidatorApiStorage { - async fn init(rocket: Rocket, database_path: PathBuf) -> fairing::Result { + pub async fn init(database_path: PathBuf) -> Result { // TODO: we can inject here more stuff based on our validator-api global config // struct. Maybe different pool size or timeout intervals? let mut opts = sqlx::sqlite::SqliteConnectOptions::new() @@ -41,13 +40,17 @@ impl ValidatorApiStorage { Ok(db) => db, Err(e) => { error!("Failed to connect to SQLx database: {}", e); - return Err(rocket); + return Err(ValidatorApiStorageError::InternalDatabaseError( + e.to_string(), + )); } }; if let Err(e) = sqlx::migrate!("./migrations").run(&connection_pool).await { error!("Failed to initialize SQLx database: {}", e); - return Err(rocket); + return Err(ValidatorApiStorageError::InternalDatabaseError( + e.to_string(), + )); } info!("Database migration finished!"); @@ -56,12 +59,12 @@ impl ValidatorApiStorage { manager: StorageManager { connection_pool }, }; - Ok(rocket.manage(storage)) + Ok(storage) } - pub(crate) fn stage(database_path: PathBuf) -> AdHoc { - AdHoc::try_on_ignite("SQLx Database", |rocket| { - ValidatorApiStorage::init(rocket, database_path) + pub(crate) fn stage(storage: ValidatorApiStorage) -> AdHoc { + AdHoc::try_on_ignite("SQLx Database", |rocket| async { + Ok(rocket.manage(storage)) }) } @@ -685,4 +688,27 @@ impl ValidatorApiStorage { .await .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(e.to_string())) } + + #[cfg(feature = "coconut")] + pub(crate) async fn get_blinded_signature_response( + &self, + tx_hash: &str, + ) -> Result, ValidatorApiStorageError> { + self.manager + .get_blinded_signature_response(tx_hash) + .await + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(e.to_string())) + } + + #[cfg(feature = "coconut")] + pub(crate) async fn insert_blinded_signature_response( + &self, + tx_hash: &str, + blinded_signature_response: &str, + ) -> Result<(), ValidatorApiStorageError> { + self.manager + .insert_blinded_signature_response(tx_hash, blinded_signature_response) + .await + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(e.to_string())) + } }