diff --git a/mithril-aggregator/src/fake_data.rs b/mithril-aggregator/src/fake_data.rs index b7df05a4421..2d2285203c8 100644 --- a/mithril-aggregator/src/fake_data.rs +++ b/mithril-aggregator/src/fake_data.rs @@ -106,9 +106,10 @@ pub fn signers(total: u64) -> Vec { // TODO: To delete once key registration is implemented #[derive(Serialize, Deserialize, Clone)] pub struct SignerWithSecretKeys { - party_id: u64, - verification_key: String, - secret_key: String, + pub party_id: u64, + pub stake: u64, + pub verification_key: String, + pub secret_key: String, } /// Fake SignerKeys returns Verification/Secret keys for a party_id diff --git a/mithril-signer/Cargo.lock b/mithril-signer/Cargo.lock index 8eef09c4c66..d376b27d2d5 100644 --- a/mithril-signer/Cargo.lock +++ b/mithril-signer/Cargo.lock @@ -14,9 +14,8 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ - "getrandom", + "getrandom 0.2.6", "once_cell", - "serde", "version_check", ] @@ -38,18 +37,160 @@ dependencies = [ "winapi", ] -[[package]] -name = "anyhow" -version = "1.0.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" - [[package]] name = "arc-swap" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5d78ce20460b82d3fa150275ed9d55e21064fc7951177baacf86a145c4a4b1f" +[[package]] +name = "ark-bls12-377" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc41c02c0d18a226947ee9ee023b1d957bdb6a68fc22ac296722935a9fef423c" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-bls12-381" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65be532f9dd1e98ad0150b037276cde464c6f371059e6dd02c0222395761f6aa" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-crypto-primitives" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff773c0ef8c655c98071d3026a63950798a66b2f45baef22d8334c1756f1bd18" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-relations", + "ark-serialize", + "ark-snark", + "ark-std", + "blake2", + "derivative", + "digest 0.9.0", +] + +[[package]] +name = "ark-ec" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea978406c4b1ca13c2db2373b05cc55429c3575b8b21f1b9ee859aa5b03dd42" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "num-bigint 0.4.3", + "num-traits", + "paste", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" +dependencies = [ + "quote 1.0.18", + "syn 1.0.91", +] + +[[package]] +name = "ark-ff-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" +dependencies = [ + "num-bigint 0.4.3", + "num-traits", + "quote 1.0.18", + "syn 1.0.91", +] + +[[package]] +name = "ark-relations" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cba4c1c99792a6834bd97f7fd76578ec2cd58d2afc5139a17e1d1bec65b38f6" +dependencies = [ + "ark-ff", + "ark-std", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "ark-serialize" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "digest 0.9.0", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dd4e5f0bf8285d5ed538d27fab7411f3e297908fd93c62195de8bee3f199e82" +dependencies = [ + "proc-macro2 1.0.37", + "quote 1.0.18", + "syn 1.0.91", +] + +[[package]] +name = "ark-snark" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc3dff1a5f67a9c0b34df32b079752d8dd17f1e9d06253da0453db6c1b7cc8a" +dependencies = [ + "ark-ff", + "ark-relations", + "ark-std", +] + +[[package]] +name = "ark-std" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + [[package]] name = "ascii-canvas" version = "3.0.0" @@ -213,9 +354,9 @@ version = "0.1.53" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed6aa3524a2dfcf9fe180c51eae2b58738348d819517ceadf95789c51fff7600" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.37", + "quote 1.0.18", + "syn 1.0.91", ] [[package]] @@ -241,6 +382,12 @@ 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 = "base64" version = "0.12.3" @@ -285,6 +432,17 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "blake2" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a4e37d16930f5459780f5621038b6382b9bb37c19016f39fb6b5808d831f174" +dependencies = [ + "crypto-mac", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + [[package]] name = "block-buffer" version = "0.7.3" @@ -372,12 +530,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" -[[package]] -name = "bytecount" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72feb31ffc86498dacdbd0fcebb56138e7177a8cc5cea4516031d15ae85a742e" - [[package]] name = "byteorder" version = "1.4.3" @@ -402,6 +554,22 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2698f953def977c68f935bb0dfa959375ad4638570e969e2f1e9f433cbf1af6" +[[package]] +name = "cbindgen" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e01024aaf5390d6a8145047371a4f5b0063a14c1e411bc731353bd2278ca44" +dependencies = [ + "clap 2.34.0", + "log", + "serde", + "serde_derive", + "serde_json", + "syn 0.15.44", + "tempfile", + "toml 0.4.10", +] + [[package]] name = "cc" version = "1.0.73" @@ -478,9 +646,9 @@ checksum = "a3aab4734e083b809aaf5794e14e756d1c798d2c69c7f7de7a09a2f5214993c1" dependencies = [ "heck 0.4.0", "proc-macro-error", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.37", + "quote 1.0.18", + "syn 1.0.91", ] [[package]] @@ -510,9 +678,9 @@ version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2af3bfb9da627b0a6c467624fb7963921433774ed435493b5c08a3053e829ad4" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.37", + "quote 1.0.18", + "syn 1.0.91", ] [[package]] @@ -527,7 +695,7 @@ dependencies = [ "chrono", "dotenv", "futures-util", - "hex 0.4.3", + "hex", "jsonwebtoken", "lazy_static", "openssl", @@ -562,7 +730,7 @@ dependencies = [ "rust-ini", "serde", "serde_json", - "toml", + "toml 0.5.9", "yaml-rust", ] @@ -636,6 +804,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array 0.14.5", + "subtle", +] + [[package]] name = "csv" version = "1.1.6" @@ -664,8 +842,8 @@ version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c" dependencies = [ - "quote", - "syn", + "quote 1.0.18", + "syn 1.0.91", ] [[package]] @@ -699,6 +877,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2 1.0.37", + "quote 1.0.18", + "syn 1.0.91", +] + [[package]] name = "diff" version = "0.1.12" @@ -829,9 +1018,9 @@ checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" [[package]] name = "fancy-regex" -version = "0.8.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d95b4efe5be9104a4a18a9916e86654319895138be727b229820c39257c30dda" +checksum = "9d6b8560a05112eb52f04b00e5d3790c0dd75d9d980eb8a122fb23b92a623ccf" dependencies = [ "bit-set", "regex", @@ -918,9 +1107,9 @@ dependencies = [ [[package]] name = "fraction" -version = "0.10.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb65943183b6b3cbf00f64c181e8178217e30194381b150e4f87ec59864c803" +checksum = "78d24d088325f939faaf806483fbfac0548e43018606bfe7a44abc83f6dc75ea" dependencies = [ "lazy_static", "num", @@ -1001,9 +1190,9 @@ version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.37", + "quote 1.0.18", + "syn 1.0.91", ] [[package]] @@ -1055,6 +1244,17 @@ dependencies = [ "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.6" @@ -1078,6 +1278,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gmp-mpfr-sys" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d00b0ef965511028498a1668c4a6ef9b0b2501a4a5ab26fb8156408869306e" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "h2" version = "0.3.13" @@ -1161,12 +1371,6 @@ dependencies = [ "libc", ] -[[package]] -name = "hex" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" - [[package]] name = "hex" version = "0.4.3" @@ -1353,15 +1557,6 @@ dependencies = [ "waker-fn", ] -[[package]] -name = "iso8601" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a59a3f2be6271b2a844cd0dd13bf8ccc88a9540482d872c7ce58ab1c4db9fab" -dependencies = [ - "nom", -] - [[package]] name = "itertools" version = "0.10.3" @@ -1405,31 +1600,25 @@ dependencies = [ [[package]] name = "jsonschema" -version = "0.15.2" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af26b80b2c3d68bd5b68d36160573f9d497cfe1cc81645a6820deed349d54f02" +checksum = "f866fd6aaffb6be509b844f988b8c8cef3194418a08f9223294c4c676f2b497f" dependencies = [ "ahash", - "anyhow", "base64 0.13.0", - "bytecount", "fancy-regex", "fraction", - "iso8601", - "itoa 1.0.1", + "itoa 0.4.8", "lazy_static", - "memchr", "num-cmp", "parking_lot", "percent-encoding", "regex", "reqwest", - "serde", "serde_json", "structopt", "time 0.3.9", "url", - "uuid", ] [[package]] @@ -1475,7 +1664,7 @@ dependencies = [ "string_cache", "term", "tiny-keccak", - "unicode-xid", + "unicode-xid 0.2.2", ] [[package]] @@ -1631,11 +1820,41 @@ dependencies = [ "winapi", ] +[[package]] +name = "mithril" +version = "0.1.0" +dependencies = [ + "ark-bls12-377", + "ark-bls12-381", + "ark-crypto-primitives", + "ark-ec", + "ark-ff", + "ark-std", + "blake2", + "bytes", + "cbindgen", + "digest 0.9.0", + "generic-array 0.14.5", + "libc", + "num-bigint 0.4.3", + "num-rational 0.4.0", + "num-traits", + "rand_core 0.6.3", + "rug", + "thiserror", + "typenum", +] + [[package]] name = "mithril-aggregator" version = "0.1.0" dependencies = [ + "ark-bls12-377", + "ark-ec", + "ark-ff", + "ark-std", "async-trait", + "blake2", "chrono", "clap 3.1.12", "clap-verbosity-flag", @@ -1644,13 +1863,17 @@ dependencies = [ "env_logger", "flate2", "futures", - "hex 0.3.2", + "hex", "http", "httpmock", "jsonschema", "log", + "mithril", "mockall", "openapiv3", + "rand 0.7.3", + "rand_chacha 0.3.1", + "rand_core 0.6.3", "reqwest", "serde", "serde_json", @@ -1667,13 +1890,24 @@ dependencies = [ name = "mithril-signer" version = "0.1.0" dependencies = [ + "ark-bls12-377", + "ark-ec", + "ark-ff", + "ark-std", + "async-trait", + "blake2", "clap 3.1.12", "cli-table", "config", "flate2", + "hex", "httpmock", + "mithril", "mithril-aggregator", "mockall", + "rand 0.7.3", + "rand_chacha 0.3.1", + "rand_core 0.6.3", "reqwest", "serde", "serde_json", @@ -1683,6 +1917,8 @@ dependencies = [ "slog-scope", "slog-term", "tar", + "thiserror", + "tokio", ] [[package]] @@ -1707,9 +1943,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79ef208208a0dea3f72221e26e904cdc6db2e481d9ade89081ddd494f1dbaa6b" dependencies = [ "cfg-if", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.37", + "quote 1.0.18", + "syn 1.0.91", ] [[package]] @@ -1724,7 +1960,7 @@ dependencies = [ "mime", "mime_guess", "quick-error", - "rand", + "rand 0.8.5", "safemem", "tempfile", "twoway", @@ -1785,11 +2021,11 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36" dependencies = [ - "num-bigint", + "num-bigint 0.2.6", "num-complex", "num-integer", "num-iter", - "num-rational", + "num-rational 0.2.4", "num-traits", ] @@ -1804,6 +2040,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-cmp" version = "0.1.0" @@ -1848,7 +2095,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" dependencies = [ "autocfg", - "num-bigint", + "num-bigint 0.2.6", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d41702bd167c2df5520b384281bc111a4b5efcf7fbc4c9c222c815b07e0a6a6a" +dependencies = [ + "autocfg", + "num-bigint 0.4.3", "num-integer", "num-traits", ] @@ -1988,6 +2247,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "paste" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc" + [[package]] name = "pathdiff" version = "0.2.1" @@ -2038,9 +2303,9 @@ checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" dependencies = [ "pest", "pest_meta", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.37", + "quote 1.0.18", + "syn 1.0.91", ] [[package]] @@ -2094,9 +2359,9 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.37", + "quote 1.0.18", + "syn 1.0.91", ] [[package]] @@ -2179,9 +2444,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.37", + "quote 1.0.18", + "syn 1.0.91", "version_check", ] @@ -2191,18 +2456,36 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.37", + "quote 1.0.18", "version_check", ] +[[package]] +name = "proc-macro2" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b06e2f335f48d24442b35a19df506a835fb3547bc3c06ef27340da9acf5cae7" +dependencies = [ + "unicode-xid 0.1.0", +] + +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +dependencies = [ + "unicode-xid 0.1.0", +] + [[package]] name = "proc-macro2" version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" dependencies = [ - "unicode-xid", + "unicode-xid 0.2.2", ] [[package]] @@ -2211,13 +2494,44 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +[[package]] +name = "quote" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8" +dependencies = [ + "proc-macro2 0.3.8", +] + +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +dependencies = [ + "proc-macro2 0.4.30", +] + [[package]] name = "quote" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" dependencies = [ - "proc-macro2", + "proc-macro2 1.0.37", +] + +[[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", ] [[package]] @@ -2227,8 +2541,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.3", +] + +[[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]] @@ -2238,7 +2562,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.3", +] + +[[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]] @@ -2247,7 +2580,16 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ - "getrandom", + "getrandom 0.2.6", +] + +[[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]] @@ -2265,7 +2607,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom", + "getrandom 0.2.6", "redox_syscall", "thiserror", ] @@ -2365,6 +2707,17 @@ dependencies = [ "serde", ] +[[package]] +name = "rug" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f829d980ca193fa33fdd1decaebe72ec07cf2d8afdd0be60b3e5391f18014c91" +dependencies = [ + "az", + "gmp-mpfr-sys", + "libc", +] + [[package]] name = "rust-ini" version = "0.18.0" @@ -2375,6 +2728,15 @@ dependencies = [ "ordered-multimap", ] +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver", +] + [[package]] name = "rustversion" version = "1.0.6" @@ -2447,24 +2809,42 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + [[package]] name = "serde" -version = "1.0.136" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +checksum = "0c4b39bd9b0b087684013a792c59e3e07a46a01d2322518d8a1104641a0b1be0" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.136" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +checksum = "ac38f51a52a556cd17545798e29536885fb1a3fa63d6399f5ef650f4a7d35901" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 0.3.8", + "quote 0.5.2", + "syn 0.13.11", ] [[package]] @@ -2591,7 +2971,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "692ca13de57ce0613a363c8c2f1de925adebc81b04c923ac60c5488bb44abe4b" dependencies = [ "chrono", - "num-bigint", + "num-bigint 0.2.6", "num-traits", ] @@ -2750,9 +3130,37 @@ checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" dependencies = [ "heck 0.3.3", "proc-macro-error", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.37", + "quote 1.0.18", + "syn 1.0.91", +] + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "0.13.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14f9bf6292f3a61d2c716723fdb789a41bbe104168e6f496dc6497e531ea1b9b" +dependencies = [ + "proc-macro2 0.3.8", + "quote 0.5.2", + "unicode-xid 0.1.0", +] + +[[package]] +name = "syn" +version = "0.15.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "unicode-xid 0.1.0", ] [[package]] @@ -2761,9 +3169,21 @@ version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d" dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", + "proc-macro2 1.0.37", + "quote 1.0.18", + "unicode-xid 0.2.2", +] + +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2 1.0.37", + "quote 1.0.18", + "syn 1.0.91", + "unicode-xid 0.2.2", ] [[package]] @@ -2840,22 +3260,22 @@ checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" [[package]] name = "thiserror" -version = "1.0.30" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.30" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.37", + "quote 1.0.18", + "syn 1.0.91", ] [[package]] @@ -2945,9 +3365,9 @@ version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.37", + "quote 1.0.18", + "syn 1.0.91", ] [[package]] @@ -3012,6 +3432,15 @@ dependencies = [ "tracing", ] +[[package]] +name = "toml" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" +dependencies = [ + "serde", +] + [[package]] name = "toml" version = "0.5.9" @@ -3046,9 +3475,9 @@ version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc6b8ad3567499f98a1db7a752b07a7c8c7c7c34c332ec00effb2b0027974b7c" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.37", + "quote 1.0.18", + "syn 1.0.91", ] [[package]] @@ -3058,6 +3487,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f" dependencies = [ "lazy_static", + "valuable", ] [[package]] @@ -3070,6 +3500,15 @@ dependencies = [ "tracing", ] +[[package]] +name = "tracing-subscriber" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" +dependencies = [ + "tracing-core", +] + [[package]] name = "try-lock" version = "0.2.3" @@ -3088,7 +3527,7 @@ dependencies = [ "http", "httparse", "log", - "rand", + "rand 0.8.5", "sha-1 0.9.8", "thiserror", "url", @@ -3152,6 +3591,12 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" + [[package]] name = "unicode-xid" version = "0.2.2" @@ -3183,10 +3628,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] -name = "uuid" -version = "0.8.2" +name = "valuable" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "value-bag" @@ -3273,6 +3718,12 @@ dependencies = [ "tracing", ] +[[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" @@ -3304,9 +3755,9 @@ dependencies = [ "bumpalo", "lazy_static", "log", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.37", + "quote 1.0.18", + "syn 1.0.91", "wasm-bindgen-shared", ] @@ -3328,7 +3779,7 @@ version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" dependencies = [ - "quote", + "quote 1.0.18", "wasm-bindgen-macro-support", ] @@ -3338,9 +3789,9 @@ version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.37", + "quote 1.0.18", + "syn 1.0.91", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3470,3 +3921,24 @@ checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" dependencies = [ "linked-hash-map", ] + +[[package]] +name = "zeroize" +version = "1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94693807d016b2f2d2e14420eb3bfcca689311ff775dcf113d74ea624b7cdf07" +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 1.0.37", + "quote 1.0.18", + "syn 1.0.91", + "synstructure", +] diff --git a/mithril-signer/Cargo.toml b/mithril-signer/Cargo.toml index 8040d098ea7..857009a6423 100644 --- a/mithril-signer/Cargo.toml +++ b/mithril-signer/Cargo.toml @@ -7,6 +7,7 @@ description = "A Mithril Signer" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +mithril = { path = "../mithril-core" } mithril-aggregator = { path = "../mithril-aggregator" } slog = { version = "2.7.0" , features = ["max_level_trace", "release_max_level_debug"] } slog-async = "2.7.0" @@ -21,7 +22,20 @@ serde_json = "1.0" reqwest = { version = "0.11", features = ["json", "stream"] } tar = "0.4.38" flate2 = "1.0.23" +thiserror = "1.0.31" +async-trait = "0.1.52" +tokio = { version = "1.17.0", features = ["full"] } -#[dev-dependencies] +hex = "0.4.3" +rand_core = "0.6.3" +rand_chacha = "0.3.1" +rand = "0.7" +ark-bls12-377 = "0.3.0" +ark-std = "0.3.0" +ark-ff = "0.3.0" +ark-ec = "0.3.0" +blake2 = "0.9.2" + +[dev-dependencies] mockall = "0.11.0" httpmock = "0.6.6" diff --git a/mithril-signer/config/dev.json b/mithril-signer/config/dev.json index a063317ae9f..387f2176894 100644 --- a/mithril-signer/config/dev.json +++ b/mithril-signer/config/dev.json @@ -1,4 +1,6 @@ { "network": "testnet", - "aggregator_endpoint": "http://localhost:8080/aggregator" + "aggregator_endpoint": "http://localhost:8080/aggregator", + "party_id": 0, + "run_interval": 20000 } \ No newline at end of file diff --git a/mithril-signer/config/testnet.json b/mithril-signer/config/testnet.json index 5e7c6d5bed5..8c758a5ec11 100644 --- a/mithril-signer/config/testnet.json +++ b/mithril-signer/config/testnet.json @@ -1,4 +1,6 @@ { "network": "testnet", - "aggregator_endpoint": "http://aggregator.api.mithril.network/aggregator" + "aggregator_endpoint": "http://aggregator.api.mithril.network/aggregator", + "party_id": 0, + "run_interval": 20000 } \ No newline at end of file diff --git a/mithril-signer/src/certificate_handler.rs b/mithril-signer/src/certificate_handler.rs new file mode 100644 index 00000000000..0dc74cc8e33 --- /dev/null +++ b/mithril-signer/src/certificate_handler.rs @@ -0,0 +1,248 @@ +use async_trait::async_trait; +use mithril_aggregator::entities::CertificatePending; +use mithril_aggregator::entities::SingleSignature; +use reqwest::{self, StatusCode}; +use slog_scope::debug; +use std::io; +use thiserror::Error; + +#[cfg(test)] +use mockall::automock; + +#[derive(Error, Debug)] +pub enum CertificateHandlerError { + #[error("remote server technical error: '{0}'")] + RemoteServerTechnical(String), + #[error("remote server logical error: '{0}'")] + RemoteServerLogical(String), + #[error("remote server unreachable: '{0}'")] + RemoteServerUnreachable(String), + #[error("json parsing failed: '{0}'")] + JsonParseFailed(String), + #[error("io error:")] + IOError(#[from] io::Error), +} + +#[cfg_attr(test, automock)] +#[async_trait] +pub trait CertificateHandler { + /// Retrieves a pending certificate from the aggregator + async fn retrieve_pending_certificate( + &self, + ) -> Result, CertificateHandlerError>; + + /// Registers single signatures with the aggregator + async fn register_signatures( + &self, + signatures: &[SingleSignature], + ) -> Result<(), CertificateHandlerError>; +} + +/// CertificateHandlerHTTPClient is a http client for an aggregator +pub struct CertificateHandlerHTTPClient { + aggregator_endpoint: String, +} + +impl CertificateHandlerHTTPClient { + /// CertificateHandlerHTTPClient factory + pub fn new(aggregator_endpoint: String) -> Self { + debug!("New CertificateHandlerHTTPClient created"); + Self { + aggregator_endpoint, + } + } +} + +#[async_trait] +impl CertificateHandler for CertificateHandlerHTTPClient { + async fn retrieve_pending_certificate( + &self, + ) -> Result, CertificateHandlerError> { + debug!("Retrieve pending certificate"); + let url = format!("{}/certificate-pending", self.aggregator_endpoint); + let response = reqwest::get(url.clone()).await; + match response { + Ok(response) => match response.status() { + StatusCode::OK => match response.json::().await { + Ok(pending_certificate) => Ok(Some(pending_certificate)), + Err(err) => Err(CertificateHandlerError::JsonParseFailed(err.to_string())), + }, + StatusCode::NO_CONTENT => Ok(None), + status_error => Err(CertificateHandlerError::RemoteServerTechnical( + status_error.to_string(), + )), + }, + Err(err) => Err(CertificateHandlerError::RemoteServerUnreachable( + err.to_string(), + )), + } + } + + async fn register_signatures( + &self, + signatures: &[SingleSignature], + ) -> Result<(), CertificateHandlerError> { + debug!("Register signatures"); + let url = format!("{}/register-signatures", self.aggregator_endpoint); + let client = reqwest::Client::new(); + let response = client.post(url.clone()).json(signatures).send().await; + match response { + Ok(response) => match response.status() { + StatusCode::CREATED => Ok(()), + StatusCode::BAD_REQUEST => Err(CertificateHandlerError::RemoteServerLogical( + "bad request".to_string(), + )), + StatusCode::CONFLICT => Err(CertificateHandlerError::RemoteServerLogical( + "already registered single signatures".to_string(), + )), + status_error => Err(CertificateHandlerError::RemoteServerTechnical( + status_error.to_string(), + )), + }, + Err(err) => Err(CertificateHandlerError::RemoteServerUnreachable( + err.to_string(), + )), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use httpmock::prelude::*; + use serde_json::json; + + use mithril_aggregator::fake_data; + + use crate::entities::Config; + + fn setup_test() -> (MockServer, Config) { + let server = MockServer::start(); + let config = Config { + network: "testnet".to_string(), + aggregator_endpoint: server.url(""), + party_id: 0, + run_interval: 100, + }; + (server, config) + } + + #[tokio::test] + async fn test_certificate_pending_ok_200() { + let (server, config) = setup_test(); + let pending_certificate_expected = fake_data::certificate_pending(); + let _snapshots_mock = server.mock(|when, then| { + when.path("/certificate-pending"); + then.status(200) + .body(json!(pending_certificate_expected).to_string()); + }); + let certificate_handler = CertificateHandlerHTTPClient::new(config.aggregator_endpoint); + let pending_certificate = certificate_handler.retrieve_pending_certificate().await; + pending_certificate.as_ref().expect("unexpected error"); + assert_eq!( + pending_certificate_expected, + pending_certificate.unwrap().unwrap() + ); + } + + #[tokio::test] + async fn test_certificate_pending_ok_204() { + let (server, config) = setup_test(); + let _snapshots_mock = server.mock(|when, then| { + when.path("/certificate-pending"); + then.status(204); + }); + let certificate_handler = CertificateHandlerHTTPClient::new(config.aggregator_endpoint); + let pending_certificate = certificate_handler.retrieve_pending_certificate().await; + assert!(pending_certificate.expect("unexpected error").is_none()); + } + + #[tokio::test] + async fn test_certificate_pending_ko_500() { + let (server, config) = setup_test(); + let _snapshots_mock = server.mock(|when, then| { + when.path("/certificate-pending"); + then.status(500); + }); + let certificate_handler = CertificateHandlerHTTPClient::new(config.aggregator_endpoint); + let pending_certificate = certificate_handler.retrieve_pending_certificate().await; + assert_eq!( + CertificateHandlerError::RemoteServerTechnical("500 Internal Server Error".to_string()) + .to_string(), + pending_certificate.unwrap_err().to_string() + ); + } + + #[tokio::test] + async fn test_register_signatures_ok_201() { + let single_signatures = fake_data::single_signatures(5); + let (server, config) = setup_test(); + let _snapshots_mock = server.mock(|when, then| { + when.method(POST).path("/register-signatures"); + then.status(201); + }); + let certificate_handler = CertificateHandlerHTTPClient::new(config.aggregator_endpoint); + let register_signatures = certificate_handler + .register_signatures(&single_signatures) + .await; + register_signatures.expect("unexpected error"); + } + + #[tokio::test] + async fn test_register_signatures_ko_400() { + let single_signatures = fake_data::single_signatures(5); + let (server, config) = setup_test(); + let _snapshots_mock = server.mock(|when, then| { + when.method(POST).path("/register-signatures"); + then.status(400); + }); + let certificate_handler = CertificateHandlerHTTPClient::new(config.aggregator_endpoint); + let register_signatures = certificate_handler + .register_signatures(&single_signatures) + .await; + assert_eq!( + CertificateHandlerError::RemoteServerLogical("bad request".to_string()).to_string(), + register_signatures.unwrap_err().to_string() + ); + } + + #[tokio::test] + async fn test_register_signatures_ko_409() { + let single_signatures = fake_data::single_signatures(5); + let (server, config) = setup_test(); + let _snapshots_mock = server.mock(|when, then| { + when.method(POST).path("/register-signatures"); + then.status(409); + }); + let certificate_handler = CertificateHandlerHTTPClient::new(config.aggregator_endpoint); + let register_signatures = certificate_handler + .register_signatures(&single_signatures) + .await; + assert_eq!( + CertificateHandlerError::RemoteServerLogical( + "already registered single signatures".to_string() + ) + .to_string(), + register_signatures.unwrap_err().to_string() + ); + } + + #[tokio::test] + async fn test_register_signatures_ko_500() { + let single_signatures = fake_data::single_signatures(5); + let (server, config) = setup_test(); + let _snapshots_mock = server.mock(|when, then| { + when.method(POST).path("/register-signatures"); + then.status(500); + }); + let certificate_handler = CertificateHandlerHTTPClient::new(config.aggregator_endpoint); + let register_signatures = certificate_handler + .register_signatures(&single_signatures) + .await; + assert_eq!( + CertificateHandlerError::RemoteServerTechnical("500 Internal Server Error".to_string()) + .to_string(), + register_signatures.unwrap_err().to_string() + ); + } +} diff --git a/mithril-signer/src/entities.rs b/mithril-signer/src/entities.rs index 0d836818d0a..33a13efd10e 100644 --- a/mithril-signer/src/entities.rs +++ b/mithril-signer/src/entities.rs @@ -11,4 +11,12 @@ pub struct Config { /// Aggregator endpoint #[table(title = "Aggregator Endpoint")] pub aggregator_endpoint: String, + + /// Party Id + #[table(title = "Party Id")] + pub party_id: u64, + + /// Run Interval + #[table(title = "Interval between two signatures attempts")] + pub run_interval: u64, } diff --git a/mithril-signer/src/main.rs b/mithril-signer/src/main.rs index fe517a84621..43b8a254fe8 100644 --- a/mithril-signer/src/main.rs +++ b/mithril-signer/src/main.rs @@ -1,11 +1,20 @@ +use crate::certificate_handler::CertificateHandlerHTTPClient; use crate::entities::Config; +use crate::signer::Signer; +use crate::single_signer::{key_decode_hex, MithrilSingleSigner}; use clap::Parser; +use mithril_aggregator::fake_data; use slog::{o, Drain, Level, Logger}; -use slog_scope::debug; +use slog_scope::{debug, error, info}; use std::env; use std::sync::Arc; +use std::time::Duration; +use tokio::time::sleep; +mod certificate_handler; mod entities; +mod signer; +mod single_signer; /// CLI args #[derive(Parser)] @@ -43,7 +52,8 @@ fn build_logger(min_level: Level) -> Logger { Logger::root(Arc::new(drain), o!()) } -fn main() { +#[tokio::main] +async fn main() { // Load args let args = Args::parse(); let _guard = slog_scope::set_global_logger(build_logger(args.log_level())); @@ -59,5 +69,20 @@ fn main() { .unwrap(); debug!("Started"; "run_mode" => &run_mode, "config" => format!("{:?}", config)); - println!("Hello, world!"); + loop { + let fake_signer = fake_data::signer_keys(config.party_id).unwrap(); + let single_signer = MithrilSingleSigner::new( + fake_signer.party_id, + key_decode_hex(&fake_signer.secret_key).unwrap(), + ); + let certificate_handler = + CertificateHandlerHTTPClient::new(config.aggregator_endpoint.clone()); + + let mut signer = Signer::new(Box::new(certificate_handler), Box::new(single_signer)); + if let Err(e) = signer.run().await { + error!("{:?}", e) + } + info!("Sleeping for {}", config.run_interval); + sleep(Duration::from_millis(config.run_interval)).await; + } } diff --git a/mithril-signer/src/signer.rs b/mithril-signer/src/signer.rs new file mode 100644 index 00000000000..d97eb42a32d --- /dev/null +++ b/mithril-signer/src/signer.rs @@ -0,0 +1,218 @@ +use thiserror::Error; + +use mithril_aggregator::entities::Beacon; +use mithril_aggregator::fake_data; + +use crate::certificate_handler::CertificateHandler; +use crate::single_signer::SingleSigner; + +pub struct Signer { + certificate_handler: Box, + single_signer: Box, + current_beacon: Option, +} + +#[derive(Error, Debug, PartialEq)] +pub enum SignerError { + #[error("single signatures computation failed: `{0}`")] + SingleSignaturesComputeFailed(String), + #[error("could not retrieve pending certificate: `{0}`")] + RetrievePendingCertificateFailed(String), +} + +impl Signer { + pub fn new( + certificate_handler: Box, + single_signer: Box, + ) -> Self { + Self { + certificate_handler, + single_signer, + current_beacon: None, + } + } + + pub async fn run(&mut self) -> Result<(), SignerError> { + if let Some(pending_certificate) = self + .certificate_handler + .retrieve_pending_certificate() + .await + .map_err(|e| SignerError::RetrievePendingCertificateFailed(e.to_string()))? + { + let must_register_signature = match &self.current_beacon { + None => { + self.current_beacon = Some(pending_certificate.beacon); + true + } + Some(beacon) => beacon != &pending_certificate.beacon, + }; + + if must_register_signature { + let message = fake_data::digest(); + let stake_distribution = fake_data::signers_with_stakes(5); + let signatures = self + .single_signer + .compute_single_signatures( + message, + stake_distribution, + &pending_certificate.protocol_parameters, + ) + .map_err(|e| SignerError::SingleSignaturesComputeFailed(e.to_string()))?; + if !signatures.is_empty() { + let _ = self + .certificate_handler + .register_signatures(&signatures) + .await; + } + } + } + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::certificate_handler::{CertificateHandlerError, MockCertificateHandler}; + use crate::single_signer::{MockSingleSigner, SingleSignerError}; + use mithril_aggregator::fake_data; + + #[tokio::test] + async fn signer_doesnt_sign_when_there_is_no_pending_certificate() { + let mut mock_certificate_handler = MockCertificateHandler::new(); + let mut mock_single_signer = MockSingleSigner::new(); + mock_certificate_handler + .expect_retrieve_pending_certificate() + .return_once(|| Ok(None)); + mock_single_signer + .expect_compute_single_signatures() + .never(); + + let mut signer = Signer::new( + Box::new(mock_certificate_handler), + Box::new(mock_single_signer), + ); + assert!(signer.run().await.is_ok()); + } + + #[tokio::test] + async fn signer_fails_when_pending_certificate_fails() { + let mut mock_certificate_handler = MockCertificateHandler::new(); + mock_certificate_handler + .expect_retrieve_pending_certificate() + .return_once(|| { + Err(CertificateHandlerError::RemoteServerTechnical( + "An Error".to_string(), + )) + }); + + let mut signer = Signer::new( + Box::new(mock_certificate_handler), + Box::new(MockSingleSigner::new()), + ); + assert_eq!( + SignerError::RetrievePendingCertificateFailed( + CertificateHandlerError::RemoteServerTechnical("An Error".to_string()).to_string() + ), + signer.run().await.unwrap_err() + ); + } + + #[tokio::test] + async fn signer_sign_when_triggered_by_pending_certificate() { + let mut mock_certificate_handler = MockCertificateHandler::new(); + let mut mock_single_signer = MockSingleSigner::new(); + let pending_certificate = fake_data::certificate_pending(); + mock_certificate_handler + .expect_retrieve_pending_certificate() + .returning(|| Ok(None)) + .once(); + mock_certificate_handler + .expect_retrieve_pending_certificate() + .return_once(|| Ok(Some(pending_certificate))); + mock_certificate_handler + .expect_register_signatures() + .return_once(|_| Ok(())); + mock_single_signer + .expect_compute_single_signatures() + .return_once(|_, _, _| Ok(fake_data::single_signatures(2))); + + let mut signer = Signer::new( + Box::new(mock_certificate_handler), + Box::new(mock_single_signer), + ); + assert!(signer.run().await.is_ok()); + assert!(signer.run().await.is_ok()); + } + + #[tokio::test] + async fn signer_sign_only_once_if_pending_certificate_has_not_changed() { + let mut mock_certificate_handler = MockCertificateHandler::new(); + let mut mock_single_signer = MockSingleSigner::new(); + let pending_certificate = fake_data::certificate_pending(); + mock_certificate_handler + .expect_retrieve_pending_certificate() + .returning(move || Ok(Some(pending_certificate.clone()))) + .times(2); + mock_certificate_handler + .expect_register_signatures() + .return_once(|_| Ok(())); + mock_single_signer + .expect_compute_single_signatures() + .return_once(|_, _, _| Ok(fake_data::single_signatures(2))); + + let mut signer = Signer::new( + Box::new(mock_certificate_handler), + Box::new(mock_single_signer), + ); + assert!(signer.run().await.is_ok()); + assert!(signer.run().await.is_ok()); + } + + #[tokio::test] + async fn signer_does_not_send_signatures_if_none_are_computed() { + let mut mock_certificate_handler = MockCertificateHandler::new(); + let mut mock_single_signer = MockSingleSigner::new(); + let pending_certificate = fake_data::certificate_pending(); + mock_certificate_handler + .expect_retrieve_pending_certificate() + .return_once(|| Ok(Some(pending_certificate))); + mock_certificate_handler + .expect_register_signatures() + .never(); + mock_single_signer + .expect_compute_single_signatures() + .return_once(|_, _, _| Ok(fake_data::single_signatures(0))); + + let mut signer = Signer::new( + Box::new(mock_certificate_handler), + Box::new(mock_single_signer), + ); + assert!(signer.run().await.is_ok()); + } + + #[tokio::test] + async fn signer_fails_if_signature_computation_fails() { + let mut mock_certificate_handler = MockCertificateHandler::new(); + let mut mock_single_signer = MockSingleSigner::new(); + let pending_certificate = fake_data::certificate_pending(); + mock_certificate_handler + .expect_retrieve_pending_certificate() + .return_once(|| Ok(Some(pending_certificate))); + mock_single_signer + .expect_compute_single_signatures() + .return_once(|_, _, _| Err(SingleSignerError::UnregisteredVerificationKey())); + + let mut signer = Signer::new( + Box::new(mock_certificate_handler), + Box::new(mock_single_signer), + ); + assert_eq!( + SignerError::SingleSignaturesComputeFailed( + SingleSignerError::UnregisteredVerificationKey().to_string() + ), + signer.run().await.unwrap_err() + ); + } +} diff --git a/mithril-signer/src/single_signer.rs b/mithril-signer/src/single_signer.rs new file mode 100644 index 00000000000..e30215563a5 --- /dev/null +++ b/mithril-signer/src/single_signer.rs @@ -0,0 +1,262 @@ +// @todo: remove this +#![allow(dead_code)] + +use ark_bls12_377::Bls12_377; +use hex::{FromHex, ToHex}; +use std::io::Cursor; +use thiserror::Error; + +use mithril::key_reg::KeyReg; +use mithril::merkle_tree::MTHashLeaf; +use mithril::mithril_proof::concat_proofs::{ConcatProof, TrivialEnv}; +use mithril::msp::{MspPk, MspSk}; +use mithril::stm::{ + Index, MTValue, PartyId, Stake, StmClerk, StmInitializer, StmMultiSig, StmParameters, StmSig, + StmSigner, +}; +use mithril_aggregator::entities; + +pub type Bytes = Vec; + +// Protocol types alias +type H = blake2::Blake2b; +type F = >>::F; +pub type ProtocolPartyId = PartyId; +pub type ProtocolStake = Stake; +pub type ProtocolStakeDistribution = Vec<(ProtocolPartyId, ProtocolStake)>; +pub type ProtocolParameters = StmParameters; +pub type ProtocolLotteryIndex = Index; +pub type ProtocolSigner = StmSigner; +pub type ProtocolInitializer = StmInitializer; +pub type ProtocolClerk = StmClerk; +pub type ProtocolKeyRegistration = KeyReg; +pub type ProtocolProof = ConcatProof; +pub type ProtocolSingleSignature = StmSig; +pub type ProtocolMultiSignature = StmMultiSig; +pub type ProtocolSignerVerificationKey = MspPk; +pub type ProtocolSignerSecretKey = MspSk; + +use mithril_aggregator::entities::{SignerWithStake, SingleSignature}; +#[cfg(test)] +use mockall::automock; +use rand_chacha::ChaCha20Rng; +use rand_core::SeedableRng; +use slog_scope::{trace, warn}; + +#[cfg_attr(test, automock)] +pub trait SingleSigner { + fn compute_single_signatures( + &self, + message: Bytes, + stake_distribution: Vec, + protocol_parameters: &entities::ProtocolParameters, + ) -> Result, SingleSignerError>; +} + +#[derive(Error, Debug, PartialEq)] +pub enum SingleSignerError { + #[error("the signer verification key is not registered in the stake distribution")] + UnregisteredVerificationKey(), + + #[error("the signer party id is not registered in the stake distribution")] + UnregisteredPartyId(), + + #[error("the protocol signer creation failed: `{0}`")] + ProtocolSignerCreationFailure(String), +} + +pub struct MithrilSingleSigner { + party_id: u64, + secret_key: ProtocolSignerSecretKey, +} + +impl MithrilSingleSigner { + pub fn new(party_id: u64, secret_key: ProtocolSignerSecretKey) -> Self { + Self { + party_id, + secret_key, + } + } + + pub fn create_protocol_signer( + &self, + current_player_stake: ProtocolStake, + stake_distribution: &[SignerWithStake], // @todo : use a hmap to prevent party id duplication + protocol_parameters: &entities::ProtocolParameters, + ) -> Result { + let players = stake_distribution + .iter() + .map(|s| (s.party_id as ProtocolPartyId, s.stake as ProtocolStake)) + .collect::>(); + let protocol_parameters = ProtocolParameters { + k: protocol_parameters.k, + m: protocol_parameters.m, + phi_f: protocol_parameters.phi_f as f64, + }; + + let mut key_reg = KeyReg::new(&players); + for s in stake_distribution { + let decoded_key = key_decode_hex(&s.verification_key)?; + key_reg + .register(s.party_id as ProtocolPartyId, decoded_key) + .unwrap(); + } + let closed_reg = key_reg.close(); + + let seed = [0u8; 32]; + let mut rng = ChaCha20Rng::from_seed(seed); + let mut initializer = StmInitializer::setup( + protocol_parameters, + self.party_id as ProtocolPartyId, + current_player_stake, + &mut rng, + ); + initializer.set_key(&self.secret_key); + + Ok(initializer.new_signer(closed_reg)) + } +} + +impl SingleSigner for MithrilSingleSigner { + fn compute_single_signatures( + &self, + message: Bytes, + stake_distribution: Vec, // @todo : use a hmap to prevent party id duplication + protocol_parameters: &entities::ProtocolParameters, + ) -> Result, SingleSignerError> { + let current_signer_with_stake = stake_distribution + .iter() + .find(|s| s.party_id == self.party_id) + .ok_or(SingleSignerError::UnregisteredPartyId())?; + + if current_signer_with_stake.verification_key.is_empty() { + return Err(SingleSignerError::UnregisteredVerificationKey()); + } + + let protocol_signer = self + .create_protocol_signer( + current_signer_with_stake.stake, + &stake_distribution, + protocol_parameters, + ) + .map_err(SingleSignerError::ProtocolSignerCreationFailure)?; + + trace!( + "Party #{}: sign message {}", + self.party_id, + message.encode_hex::() + ); + + let mut signatures = Vec::new(); + for i in 1..=protocol_parameters.m { + if let Some(signature) = protocol_signer.sign(&message, i) { + trace!("Party #{}: lottery #{} won", self.party_id, i,); + let encoded_signature = key_encode_hex(signature); + + if encoded_signature.is_err() { + warn!("couldn't compute signature: `{:?}`", encoded_signature); // @todo: structured log + continue; + } + + signatures.push(SingleSignature::new( + self.party_id, + i, + encoded_signature.unwrap(), + )); + } + } + Ok(signatures) + } +} + +/// Encode key to hex helper +pub fn key_encode_hex(from: T) -> Result { + Ok(ark_ff::to_bytes!(from) + .map_err(|e| format!("can't convert to hex: {}", e))? + .encode_hex::()) +} + +/// Decode key from hex helper +pub fn key_decode_hex(from: &str) -> Result { + ark_ff::FromBytes::read(Cursor::new( + Vec::from_hex(from).map_err(|e| format!("can't parse from hex: {}", e))?, + )) + .map_err(|e| format!("can't convert to bytes: {}", e)) +} + +#[cfg(test)] +mod tests { + use super::*; + use mithril_aggregator::fake_data; + + #[test] + fn cant_compute_if_signer_verification_key_is_not_registered() { + let signer_with_keys = fake_data::signer_keys(0).unwrap(); + let single_signer = MithrilSingleSigner::new( + signer_with_keys.party_id, + key_decode_hex(&signer_with_keys.secret_key).unwrap(), + ); + let stake_distribution = fake_data::signers_with_stakes(5) + .into_iter() + .map(|s| { + if s.party_id == signer_with_keys.party_id { + SignerWithStake { + party_id: s.party_id, + verification_key: "".to_string(), + stake: s.stake, + } + } else { + s + } + }) + .collect(); + let protocol_parameters = fake_data::protocol_parameters(); + + let sign_result = single_signer.compute_single_signatures( + "message".as_bytes().to_vec(), + stake_distribution, + &protocol_parameters, + ); + + assert_eq!( + SingleSignerError::UnregisteredVerificationKey(), + sign_result.unwrap_err() + ) + } + + #[test] + fn should_produce_a_single_signature() { + let signer_with_keys = fake_data::signer_keys(0).unwrap(); + let single_signer = MithrilSingleSigner::new( + signer_with_keys.party_id, + key_decode_hex(&signer_with_keys.secret_key).unwrap(), + ); + let stake_distribution = fake_data::signers_with_stakes(5); + let protocol_parameters = fake_data::protocol_parameters(); + let protocol_signer: ProtocolSigner = single_signer + .create_protocol_signer( + signer_with_keys.stake, + &stake_distribution, + &protocol_parameters, + ) + .unwrap(); + let clerk = StmClerk::from_signer(&protocol_signer, TrivialEnv); + + let message = "message".as_bytes(); + let sign_result = single_signer.compute_single_signatures( + message.to_vec(), + stake_distribution, + &protocol_parameters, + ); + + assert!(!sign_result.as_ref().unwrap().is_empty()); + for sig in sign_result.unwrap() { + let decoded_sig = key_decode_hex(&sig.signature).unwrap(); + assert!(clerk.verify_sig(&decoded_sig, sig.index, message).is_ok()); + assert_eq!( + decoded_sig.pk, + key_decode_hex(&signer_with_keys.verification_key).unwrap() + ); + } + } +} diff --git a/openapi.yaml b/openapi.yaml index e14e098757c..bb6b0b76f19 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -32,6 +32,8 @@ paths: application/json: schema: $ref: "#/components/schemas/CertificatePending" + "204": + description: no pending certificate available default: description: pending certificate error content: