commit f2afc13ea29569a8fe34e6d598f1f43f750ea961 Author: DieMyst Date: Fri Jan 15 19:37:06 2021 +0300 INIT diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..741639c --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1533 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "addr2line" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" + +[[package]] +name = "anyhow" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1" + +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + +[[package]] +name = "asn1_der" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fce6b6a0ffdafebd82c87e79e3f40e8d2c523e5fea5566ff6b90509bf98d638" +dependencies = [ + "asn1_der_derive", +] + +[[package]] +name = "asn1_der_derive" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d0864d84b8e07b145449be9a8537db86bf9de5ce03b913214694643b4743502" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "backtrace" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef5140344c85b01f9bbb4d4b7288a8aa4b3287ccef913a14bcc78a1063623598" +dependencies = [ + "addr2line", + "cfg-if 1.0.0", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[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.3", +] + +[[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 = "bs58" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "476e9cd489f9e121e02ffa6014a8ef220ecb15c05ed23fc34cca13925dc283fb" + +[[package]] +name = "bs58" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" + +[[package]] +name = "bumpalo" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" + +[[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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" + +[[package]] +name = "bytes" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" + +[[package]] +name = "cc" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cpuid-bool" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[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.3", + "subtle 1.0.0", +] + +[[package]] +name = "curve25519-dalek" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f627126b946c25a4638eec0ea634fc52506dea98db118aae985118ce7c3d723f" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle 2.4.0", + "zeroize", +] + +[[package]] +name = "data-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993a608597367c6377b258c25d7120740f00ed23a2252b729b1932dd7866f908" + +[[package]] +name = "derivative" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaed5874effa6cde088c644ddcdcb4ffd1511391c5be4fdd7a5ccd02c7e4a183" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array 0.12.3", +] + +[[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 = "ed25519" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37c66a534cbb46ab4ea03477eae19d5c22c01da8258030280b7bd9d8433fb6ef" +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 0.9.2", + "zeroize", +] + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "failure" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" +dependencies = [ + "backtrace", + "failure_derive", +] + +[[package]] +name = "failure_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" + +[[package]] +name = "fixedbitset" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" + +[[package]] +name = "fluence-fork-libp2p-core" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e144c2f2e2d915fcdf1d4a413093e793950da7479603297f97450ac1aedadf" +dependencies = [ + "asn1_der", + "bs58 0.4.0", + "ed25519-dalek", + "either", + "fluence-fork-multistream-select", + "fluence-fork-parity-multiaddr", + "fnv", + "futures", + "futures-timer", + "lazy_static", + "libsecp256k1", + "log", + "multihash", + "parking_lot", + "pin-project 1.0.4", + "prost", + "prost-build", + "rand 0.7.3", + "ring", + "rw-stream-sink", + "serde", + "sha2 0.9.2", + "smallvec", + "thiserror", + "unsigned-varint", + "void", + "zeroize", +] + +[[package]] +name = "fluence-fork-multistream-select" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fe6c01231db8700221a08cdd429575099d8727c2ca0500427b57b1aa9e03bbb" +dependencies = [ + "bytes", + "futures", + "log", + "pin-project 1.0.4", + "smallvec", + "unsigned-varint", +] + +[[package]] +name = "fluence-fork-parity-multiaddr" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee001eadfcb415fbc4a39b73c999d5c39afcf040100807653ea420ca13fbc23a" +dependencies = [ + "arrayref", + "bs58 0.4.0", + "byteorder", + "data-encoding", + "multihash", + "percent-encoding", + "serde", + "static_assertions", + "unsigned-varint", + "url", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ece68d15c92e84fa4f19d3780f1294e5ca82a78a6d515f1efaabcc144688be00" +dependencies = [ + "matches", + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9052a1a50244d8d5aa9bf55cbc2fb6f357c86cc52e46c62ed390a7180cf150" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2d31b7ec7efab6eefc7c57233bb10b847986139d88cc2f5a02a1ae6871a1846" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79e5145dde8da7d1b3892dad07a9c98fc04bc39892b1ecc9692cf53e2b780a65" + +[[package]] +name = "futures-executor" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9e59fdc009a4b3096bf94f740a0f2424c082521f20a9b08c5c07c48d90fd9b9" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", + "num_cpus", +] + +[[package]] +name = "futures-io" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28be053525281ad8259d47e4de5de657b25e7bac113458555bb4b70bc6870500" + +[[package]] +name = "futures-macro" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c287d25add322d9f9abdcdc5927ca398917996600182178774032e9f8258fedd" +dependencies = [ + "proc-macro-hack", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf5c69029bda2e743fddd0582d1083951d65cc9539aebf8812f36c3491342d6" + +[[package]] +name = "futures-task" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13de07eb8ea81ae445aca7b69f5f7bf15d7bf4912d8ca37d6645c77ae8a58d86" +dependencies = [ + "once_cell", +] + +[[package]] +name = "futures-timer" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" + +[[package]] +name = "futures-util" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "632a8cd0f2a4b3fdea1657f08bde063848c3bd00f9bbf6e256b8be78802e624b" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "proc-macro-hack", + "proc-macro-nested", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" +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 1.0.0", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4060f4657be78b8e766215b02b18a2e862d83745545de804638e2b545e81aee6" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi 0.10.1+wasi-snapshot-preview1", +] + +[[package]] +name = "gimli" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" + +[[package]] +name = "hashbrown" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" + +[[package]] +name = "heck" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" +dependencies = [ + "libc", +] + +[[package]] +name = "hmac" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" +dependencies = [ + "crypto-mac", + "digest 0.8.1", +] + +[[package]] +name = "hmac-drbg" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6e570451493f10f6581b48cdd530413b63ea9e780f544bfd3bdcaa0d89d1a7b" +dependencies = [ + "digest 0.8.1", + "generic-array 0.12.3", + "hmac", +] + +[[package]] +name = "idna" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "instant" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "itertools" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" + +[[package]] +name = "js-sys" +version = "0.3.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d7383929f7c9c7c2d0fa596f325832df98c3704f2c60553080f7127a58175" +dependencies = [ + "wasm-bindgen", +] + +[[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.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929" + +[[package]] +name = "libsecp256k1" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc1e2c808481a63dc6da2074752fdd4336a3c8fcc68b83db6f1fd5224ae7962" +dependencies = [ + "arrayref", + "crunchy", + "digest 0.8.1", + "hmac-drbg", + "rand 0.7.3", + "sha2 0.8.2", + "subtle 2.4.0", + "typenum", +] + +[[package]] +name = "lock_api" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf3805d4480bb5b86070dcfeb9e2cb2ebc148adb753c5cca5f884d1d65a42b2" +dependencies = [ + "cfg-if 0.1.10", +] + +[[package]] +name = "matches" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" + +[[package]] +name = "memchr" +version = "2.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" + +[[package]] +name = "miniz_oxide" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d" +dependencies = [ + "adler", + "autocfg", +] + +[[package]] +name = "multihash" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dac63698b887d2d929306ea48b63760431ff8a24fac40ddb22f9c7f49fb7cab" +dependencies = [ + "digest 0.9.0", + "generic-array 0.14.4", + "multihash-derive", + "sha2 0.9.2", + "unsigned-varint", +] + +[[package]] +name = "multihash-derive" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85ee3c48cb9d9b275ad967a0e96715badc13c6029adb92f34fa17b9ff28fd81f" +dependencies = [ + "proc-macro-crate", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "multimap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1255076139a83bb467426e7f8d0134968a8118844faa755985e077cf31850333" + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" + +[[package]] +name = "once_cell" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" + +[[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 = "parking_lot" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ccb628cad4f84851442432c60ad8e1f607e29752d0bf072cbd0baf28aa34272" +dependencies = [ + "cfg-if 1.0.0", + "instant", + "libc", + "redox_syscall 0.1.57", + "smallvec", + "winapi", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "petgraph" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "pin-project" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ffbc8e94b38ea3d2d8ba92aea2983b503cd75d0888d75b86bb37970b5698e15" +dependencies = [ + "pin-project-internal 0.4.27", +] + +[[package]] +name = "pin-project" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b70b68509f17aa2857863b6fa00bf21fc93674c7a8893de2f469f6aa7ca2f2" +dependencies = [ + "pin-project-internal 1.0.4", +] + +[[package]] +name = "pin-project-internal" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65ad2ae56b6abe3a1ee25f15ee605bacadb9a764edaba9c2bf4103800d4a1895" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa25a6393f22ce819b0f50e0be89287292fda8d425be38ee0ca14c4931d9e71" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439697af366c49a6d0a010c56a0d97685bc140ce0d377b13a2ea2aa42d64a827" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" + +[[package]] +name = "proc-macro-crate" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml", +] + +[[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-macro-hack" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" + +[[package]] +name = "proc-macro-nested" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" + +[[package]] +name = "proc-macro2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "prost" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce49aefe0a6144a45de32927c77bd2859a5f7677b55f220ae5b744e87389c212" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b10678c913ecbd69350e8535c3aef91a8676c0773fc1d7b95cdd196d7f2f26" +dependencies = [ + "bytes", + "heck", + "itertools", + "log", + "multimap", + "petgraph", + "prost", + "prost-types", + "tempfile", + "which", +] + +[[package]] +name = "prost-derive" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537aa19b95acde10a12fec4301466386f757403de4cd4e5b4fa78fb5ecb18f72" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "prost-types" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1834f67c0697c001304b75be76f67add9c89742eda3a085ad8ee0bb38c3417aa" +dependencies = [ + "bytes", + "prost", +] + +[[package]] +name = "quote" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" +dependencies = [ + "proc-macro2", +] + +[[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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18519b42a40024d661e1714153e9ad0c3de27cd495760ceb09710920f1098b1e" +dependencies = [ + "libc", + "rand_chacha 0.3.0", + "rand_core 0.6.1", + "rand_hc 0.3.0", +] + +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.1", +] + +[[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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c026d7df8b298d90ccbbc5190bd04d85e159eaf5576caeacf8741da93ccbd2e5" +dependencies = [ + "getrandom 0.2.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_hc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" +dependencies = [ + "rand_core 0.6.1", +] + +[[package]] +name = "redox_syscall" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" + +[[package]] +name = "redox_syscall" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ec8ca9416c5ea37062b502703cd7fcb207736bc294f6e0cf367ac6fc234570" +dependencies = [ + "bitflags", +] + +[[package]] +name = "ref-cast" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300f2a835d808734ee295d45007adacb9ebb29dd3ae2424acfa17930cae541da" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c38e3aecd2b21cb3959637b883bb3714bc7e43f0268b9a29d3743ee3e55cdd2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[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 = "ring" +version = "0.16.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "024a1e66fea74c66c66624ee5622a7ff0e4b73a13b4f5c326ddb50c708944226" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232" + +[[package]] +name = "rw-stream-sink" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4da5fcb054c46f5a5dff833b129285a93d3f0179531735e6c866e8cc307d2020" +dependencies = [ + "futures", + "pin-project 0.4.27", + "static_assertions", +] + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.118" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.118" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" +dependencies = [ + "block-buffer 0.7.3", + "digest 0.8.1", + "fake-simd", + "opaque-debug 0.2.3", +] + +[[package]] +name = "sha2" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e7aab86fe2149bad8c507606bdb3f4ef5e7b2380eb92350f56122cca72a42a8" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if 1.0.0", + "cpuid-bool", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + +[[package]] +name = "signature" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f0242b8e50dd9accdd56170e94ca1ebd223b098eb9c83539a6e367d0f36ae68" + +[[package]] +name = "slab" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" + +[[package]] +name = "smallvec" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" + +[[package]] +name = "syn" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc60a3d73ea6594cd712d830cc1f0390fd71542d8c8cd24e70cc54cdfd5e05d5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "synstructure" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + +[[package]] +name = "tempfile" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "rand 0.8.2", + "redox_syscall 0.2.4", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "thiserror" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76cc616c6abf8c8928e2fdcc0dbfab37175edd8fb49a4641066ad1364fdab146" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinyvec" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf8dbc19eb42fba10e8feaaec282fb50e2c14b2726d6301dbfeed0f73306a6f" +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 = "trust-graph" +version = "0.2.0" +dependencies = [ + "bs58 0.3.1", + "derivative", + "ed25519-dalek", + "failure", + "fluence-fork-libp2p-core", + "log", + "rand 0.7.3", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "typenum" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" + +[[package]] +name = "unicode-bidi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" +dependencies = [ + "matches", +] + +[[package]] +name = "unicode-normalization" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a13e63ab62dbe32aeee58d1c5408d35c36c392bba5d9d3142287219721afe606" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" + +[[package]] +name = "unsigned-varint" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fdeedbf205afadfe39ae559b75c3240f24e257d0ca27e85f85cb82aa19ac35" + +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5909f2b0817350449ed73e8bcd81c8c3c8d9a7a5d8acba4b27db277f1868976e" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", +] + +[[package]] +name = "version_check" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[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.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93c6c3420963c5c64bca373b25e77acb562081b9bb4dd5bb864187742186cea9" + +[[package]] +name = "wasm-bindgen" +version = "0.2.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cd364751395ca0f68cafb17666eee36b63077fb5ecd972bbcd74c90c4bf736e" +dependencies = [ + "cfg-if 1.0.0", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1114f89ab1f4106e5b55e688b828c0ab0ea593a1ea7c094b141b14cbaaec2d62" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6ac8995ead1f084a8dea1e65f194d0973800c7f571f6edd70adf06ecf77084" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a48c72f299d80557c7c62e37e7225369ecc0c963964059509fbafe917c7549" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e7811dd7f9398f14cc76efd356f98f03aa30419dea46aa810d71e819fc97158" + +[[package]] +name = "web-sys" +version = "0.3.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222b1ef9334f92a21d3fb53dc3fd80f30836959a90f9274a626d7e06315ba3c3" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "which" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724" +dependencies = [ + "libc", +] + +[[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-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "zeroize" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81a974bcdd357f0dca4d41677db03436324d45a4c9ed2d0b873a5a360ce41c36" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3f369ddb18862aba61aa49bf31e74d29f0f162dec753063200e1dc084345d16" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..be1dab9 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "trust-graph" +version = "0.2.0" +authors = ["Fluence Labs"] +edition = "2018" +description = "trust graph" +license = "Apache-2.0" + +[dependencies] +libp2p-core = { package = "fluence-fork-libp2p-core", version = "0.26.0" } +serde = { version = "=1.0.118", features = ["derive"] } +serde_json = "1.0.58" +bs58 = "0.3.1" +failure = "0.1.6" +log = "0.4.11" +ref-cast = "1.0.2" +derivative = "2.1.1" +ed25519-dalek = "1.0.1" + +[dev-dependencies] +rand = "0.7.3" diff --git a/src/certificate.rs b/src/certificate.rs new file mode 100644 index 0000000..8f1b1a7 --- /dev/null +++ b/src/certificate.rs @@ -0,0 +1,532 @@ +/* + * Copyright 2020 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::ed25519::PublicKey; +use crate::key_pair::KeyPair; +use crate::trust::{Trust, TRUST_LEN}; +use std::str::FromStr; +use std::time::Duration; + +/// Serialization format of a certificate. +/// TODO +const FORMAT: &[u8; 2] = &[0, 0]; +/// Serialization format version of a certificate. +/// TODO +const VERSION: &[u8; 4] = &[0, 0, 0, 0]; + +/// Chain of trusts started from self-signed root trust. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Certificate { + pub chain: Vec, +} + +impl Certificate { + pub fn new_unverified(chain: Vec) -> Self { + Self { chain } + } + + /// Creates new certificate with root trust (self-signed public key) from a key pair. + #[allow(dead_code)] + pub fn issue_root( + root_kp: &KeyPair, + for_pk: PublicKey, + expires_at: Duration, + issued_at: Duration, + ) -> Self { + let root_expiration = Duration::from_secs(u64::max_value()); + + let root_trust = Trust::create(root_kp, root_kp.public_key(), root_expiration, issued_at); + + let trust = Trust::create(root_kp, for_pk, expires_at, issued_at); + + let chain = vec![root_trust, trust]; + Self { chain } + } + + /// Adds a new trust into chain of trust in certificate. + #[allow(dead_code)] + pub fn issue( + issued_by: &KeyPair, + for_pk: PublicKey, + extend_cert: &Certificate, + expires_at: Duration, + issued_at: Duration, + cur_time: Duration, + ) -> Result { + if expires_at.lt(&issued_at) { + return Err("Expiration time should be greater than issued time.".to_string()); + } + + // first, verify given certificate + Certificate::verify( + extend_cert, + &[extend_cert.chain[0].issued_for.clone()], + cur_time, + )?; + + let issued_by_pk = issued_by.public_key(); + + // check if `issued_by_pk` is allowed to issue a certificate (i.e., there’s a trust for it in a chain) + let mut previous_trust_num: i32 = -1; + for pk_id in 0..extend_cert.chain.len() { + if extend_cert.chain[pk_id].issued_for == issued_by_pk { + previous_trust_num = pk_id as i32; + } + } + + if previous_trust_num == -1 { + return Err("Your public key should be in certificate.".to_string()); + }; + + // splitting old chain to add new trust after given public key + let mut new_chain = extend_cert + .chain + .split_at((previous_trust_num + 1) as usize) + .0 + .to_vec(); + + let trust = Trust::create(issued_by, for_pk, expires_at, issued_at); + + new_chain.push(trust); + + Ok(Self { chain: new_chain }) + } + + /// Verifies that a certificate is valid and you trust to this certificate. + pub fn verify( + cert: &Certificate, + trusted_roots: &[PublicKey], + cur_time: Duration, + ) -> Result<(), String> { + let chain = &cert.chain; + + if chain.is_empty() { + return Err("The certificate must have at least 1 trust".to_string()); + } + + // check root trust and its existence in trusted roots list + let root = &chain[0]; + Trust::verify(root, &root.issued_for, cur_time) + .map_err(|e| format!("Root trust did not pass verification: {}", e))?; + if !trusted_roots.contains(&root.issued_for) { + return Err("Certificate does not contain a trusted root.".to_string()); + } + + // check if every element in a chain is not expired and has the correct signature + for trust_id in (1..chain.len()).rev() { + let trust = &chain[trust_id]; + + let trust_giver = &chain[trust_id - 1]; + + Trust::verify(trust, &trust_giver.issued_for, cur_time).map_err(|e| { + format!( + "Trust {} in chain did not pass verification: {}", + trust_id, e + ) + })?; + } + + Ok(()) + } + + /// Convert certificate to byte format + /// 2 format + 4 version + (64 signature + 32 public key + 8 expiration) * number of trusts + #[allow(dead_code)] + pub fn encode(&self) -> Vec { + let mut encoded = + Vec::with_capacity(FORMAT.len() + VERSION.len() + TRUST_LEN * self.chain.len()); + encoded.extend_from_slice(FORMAT); + encoded.extend_from_slice(VERSION); + + for t in &self.chain { + encoded.extend(t.encode()); + } + + encoded + } + + #[allow(dead_code)] + pub fn decode(arr: &[u8]) -> Result { + let trusts_offset = arr.len() - 2 - 4; + if trusts_offset % TRUST_LEN != 0 { + return Err("Incorrect length of an array. Should be 2 bytes of a format, 4 bytes of a version and 104 bytes for each trust. ".to_string()); + } + + let number_of_trusts = trusts_offset / TRUST_LEN; + + if number_of_trusts < 2 { + return Err("The certificate must have at least 2 trusts.".to_string()); + } + + // TODO do match different formats and versions + let _format = &arr[0..1]; + let _version = &arr[2..5]; + + let mut chain = Vec::with_capacity(number_of_trusts); + + for i in 0..number_of_trusts { + let from = i * TRUST_LEN + 6; + let to = (i + 1) * TRUST_LEN + 6; + let slice = &arr[from..to]; + let t = Trust::decode(slice)?; + chain.push(t); + } + + Ok(Self { chain }) + } +} + +impl std::fmt::Display for Certificate { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!(f, "{}", bs58::encode(FORMAT).into_string())?; + writeln!(f, "{}", bs58::encode(VERSION).into_string())?; + for trust in self.chain.iter() { + writeln!(f, "{}", trust.to_string())?; + } + Ok(()) + } +} + +impl FromStr for Certificate { + type Err = String; + + fn from_str(s: &str) -> Result { + let str_lines: Vec<&str> = s.lines().collect(); + + // TODO for future purposes + let _format = str_lines[0]; + let _version = str_lines[1]; + + if (str_lines.len() - 2) % 4 != 0 { + return Err(format!("Incorrect format of the certificate: {}", s)); + } + + let num_of_trusts = (str_lines.len() - 2) / 4; + let mut trusts = Vec::with_capacity(num_of_trusts); + + for i in (2..str_lines.len()).step_by(4) { + let trust = Trust::convert_from_strings( + str_lines[i], + str_lines[i + 1], + str_lines[i + 2], + str_lines[i + 3], + )?; + + trusts.push(trust); + } + + Ok(Self::new_unverified(trusts)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::misc::current_time; + use std::time::{Duration, SystemTime, UNIX_EPOCH}; + + pub fn one_second() -> Duration { + Duration::from_secs(1) + } + + pub fn one_minute() -> Duration { + Duration::from_secs(60) + } + + pub fn one_year() -> Duration { + Duration::from_secs(31_557_600) + } + + #[test] + pub fn test_string_encoding_decoding() { + let (_root_kp, second_kp, cert) = generate_root_cert(); + + let cur_time = current_time(); + + let third_kp = KeyPair::generate(); + + let new_cert = Certificate::issue( + &second_kp, + third_kp.key_pair.public(), + &cert, + cur_time.checked_add(one_second()).unwrap(), + cur_time, + cur_time, + ) + .unwrap(); + + let serialized = new_cert.to_string(); + let deserialized = Certificate::from_str(&serialized); + + assert!(deserialized.is_ok()); + let after_cert = deserialized.unwrap(); + assert_eq!(&new_cert.chain[0], &after_cert.chain[0]); + assert_eq!(&new_cert, &after_cert); + } + + #[test] + pub fn test_serialization_deserialization() { + let (_root_kp, second_kp, cert) = generate_root_cert(); + + let cur_time = current_time(); + + let third_kp = KeyPair::generate(); + + let new_cert = Certificate::issue( + &second_kp, + third_kp.key_pair.public(), + &cert, + cur_time.checked_add(one_second()).unwrap(), + cur_time, + cur_time, + ) + .unwrap(); + + let serialized = new_cert.encode(); + let deserialized = Certificate::decode(serialized.as_slice()); + + assert!(deserialized.is_ok()); + let after_cert = deserialized.unwrap(); + assert_eq!(&new_cert.chain[0], &after_cert.chain[0]); + assert_eq!(&new_cert, &after_cert); + } + + #[test] + fn test_small_chain() { + let bad_cert = Certificate { chain: Vec::new() }; + + let check = Certificate::verify(&bad_cert, &[], current_time()); + assert!(check.is_err()); + } + + fn generate_root_cert() -> (KeyPair, KeyPair, Certificate) { + let root_kp = KeyPair::generate(); + let second_kp = KeyPair::generate(); + + let cur_time = current_time(); + + ( + root_kp.clone(), + second_kp.clone(), + Certificate::issue_root( + &root_kp, + second_kp.public_key(), + cur_time.checked_add(one_year()).unwrap(), + cur_time, + ), + ) + } + + #[test] + fn test_issue_cert() { + let (root_kp, second_kp, cert) = generate_root_cert(); + let trusted_roots = [root_kp.public_key()]; + + // we don't need nanos for serialization, etc + let cur_time = Duration::from_secs( + SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs() as u64, + ); + + let third_kp = KeyPair::generate(); + + let new_cert = Certificate::issue( + &second_kp, + third_kp.key_pair.public(), + &cert, + cur_time.checked_add(one_year()).unwrap(), + cur_time, + cur_time, + ); + assert_eq!(new_cert.is_ok(), true); + let new_cert = new_cert.unwrap(); + + println!( + "root_kp:\n\tprivate: {}\n\tpublic: {}", + bs58::encode(root_kp.key_pair.secret()).into_string(), + bs58::encode(&root_kp.key_pair.public().encode().to_vec()).into_string() + ); + println!( + "second_kp:\n\tprivate: {}\n\tpublic: {}", + bs58::encode(second_kp.key_pair.secret()).into_string(), + bs58::encode(&second_kp.key_pair.public().encode().to_vec()).into_string() + ); + println!( + "third_kp:\n\tprivate: {}\n\tpublic: {}", + bs58::encode(third_kp.key_pair.secret()).into_string(), + bs58::encode(&third_kp.key_pair.public().encode().to_vec()).into_string() + ); + println!("cert is\n{}", new_cert.to_string()); + + assert_eq!(new_cert.chain.len(), 3); + assert_eq!(new_cert.chain[0].issued_for, root_kp.public_key()); + assert_eq!(new_cert.chain[1].issued_for, second_kp.public_key()); + assert_eq!(new_cert.chain[2].issued_for, third_kp.public_key()); + assert!(Certificate::verify(&new_cert, &trusted_roots, cur_time).is_ok()); + } + + #[test] + fn test_cert_expiration() { + let (root_kp, second_kp, cert) = generate_root_cert(); + let trusted_roots = [root_kp.public_key()]; + let cur_time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); + + let third_kp = KeyPair::generate(); + + let new_cert = Certificate::issue( + &second_kp, + third_kp.key_pair.public(), + &cert, + cur_time.checked_sub(one_second()).unwrap(), + cur_time.checked_sub(one_minute()).unwrap(), + cur_time, + ) + .unwrap(); + + assert!(Certificate::verify(&new_cert, &trusted_roots, cur_time).is_err()); + } + + #[test] + fn test_issue_in_chain_tail() { + let (root_kp, second_kp, cert) = generate_root_cert(); + let trusted_roots = [root_kp.public_key()]; + let cur_time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); + + let third_kp = KeyPair::generate(); + let fourth_kp = KeyPair::generate(); + + let new_cert = Certificate::issue( + &second_kp, + third_kp.key_pair.public(), + &cert, + cur_time.checked_add(one_second()).unwrap(), + cur_time, + cur_time, + ) + .unwrap(); + let new_cert = Certificate::issue( + &third_kp, + fourth_kp.key_pair.public(), + &new_cert, + cur_time.checked_add(one_second()).unwrap(), + cur_time, + cur_time, + ); + + assert_eq!(new_cert.is_ok(), true); + let new_cert = new_cert.unwrap(); + + assert_eq!(new_cert.chain.len(), 4); + assert_eq!(new_cert.chain[0].issued_for, root_kp.public_key()); + assert_eq!(new_cert.chain[1].issued_for, second_kp.public_key()); + assert_eq!(new_cert.chain[2].issued_for, third_kp.public_key()); + assert_eq!(new_cert.chain[3].issued_for, fourth_kp.public_key()); + assert!(Certificate::verify(&new_cert, &trusted_roots, cur_time).is_ok()); + } + + #[test] + fn test_issue_in_chain_body() { + let (root_kp, second_kp, cert) = generate_root_cert(); + let trusted_roots = [root_kp.public_key()]; + let cur_time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); + + let third_kp = KeyPair::generate(); + let fourth_kp = KeyPair::generate(); + + let new_cert = Certificate::issue( + &second_kp, + third_kp.key_pair.public(), + &cert, + cur_time.checked_add(one_second()).unwrap(), + cur_time, + cur_time, + ) + .unwrap(); + let new_cert = Certificate::issue( + &second_kp, + fourth_kp.key_pair.public(), + &new_cert, + cur_time.checked_add(one_second()).unwrap(), + cur_time, + cur_time, + ); + + assert_eq!(new_cert.is_ok(), true); + let new_cert = new_cert.unwrap(); + + assert_eq!(new_cert.chain.len(), 3); + assert_eq!(new_cert.chain[0].issued_for, root_kp.public_key()); + assert_eq!(new_cert.chain[1].issued_for, second_kp.public_key()); + assert_eq!(new_cert.chain[2].issued_for, fourth_kp.public_key()); + assert!(Certificate::verify(&new_cert, &trusted_roots, cur_time).is_ok()); + } + + #[test] + fn test_no_cert_in_chain() { + let (_root_kp, _second_kp, cert) = generate_root_cert(); + let cur_time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); + + let bad_kp = KeyPair::generate(); + let new_cert_bad = Certificate::issue( + &bad_kp, + bad_kp.key_pair.public(), + &cert, + cur_time.checked_add(one_second()).unwrap(), + cur_time, + cur_time, + ); + assert_eq!(new_cert_bad.is_err(), true); + } + + #[test] + fn test_no_trusted_root_in_chain() { + let (_root_kp, second_kp, cert) = generate_root_cert(); + let cur_time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); + + let trusted_roots = [second_kp.public_key()]; + assert!(Certificate::verify(&cert, &trusted_roots, cur_time).is_err()); + assert!(Certificate::verify(&cert, &[], cur_time).is_err()); + } + + #[test] + fn test_forged_cert() { + let (root_kp, _second_kp, cert) = generate_root_cert(); + let cur_time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); + let trusted_roots = [root_kp.public_key()]; + + // forged cert + let mut bad_chain = cert.chain; + bad_chain.remove(0); + let bad_cert = Certificate { chain: bad_chain }; + + assert!(Certificate::verify(&bad_cert, &trusted_roots, cur_time).is_err()); + } + + #[test] + fn test_generate_root_cert() { + let (root_kp, second_kp, cert) = generate_root_cert(); + let cur_time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); + + let trusted_roots = [root_kp.public_key()]; + + assert_eq!(cert.chain.len(), 2); + assert_eq!(cert.chain[0].issued_for, root_kp.public_key()); + assert_eq!(cert.chain[1].issued_for, second_kp.public_key()); + assert!(Certificate::verify(&cert, &trusted_roots, cur_time).is_ok()); + } +} diff --git a/src/certificate_serde.rs b/src/certificate_serde.rs new file mode 100644 index 0000000..6012fab --- /dev/null +++ b/src/certificate_serde.rs @@ -0,0 +1,71 @@ +/* + * Copyright 2020 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::Certificate; +use serde::de::Error; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use std::str::FromStr; + +mod single { + #![allow(dead_code)] + use super::*; + pub fn serialize(value: &Certificate, serializer: S) -> Result + where + S: Serializer, + { + value.to_string().serialize(serializer) + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let str = String::deserialize(deserializer)?; + Certificate::from_str(&str) + .map_err(|e| Error::custom(format!("certificate deserialization failed for {:?}", e))) + } +} + +pub mod vec { + use super::*; + use serde::ser::SerializeSeq; + + pub fn serialize(value: &[Certificate], serializer: S) -> Result + where + S: Serializer, + { + let mut seq = serializer.serialize_seq(Some(value.len()))?; + for e in value { + let e = e.to_string(); + seq.serialize_element(&e)?; + } + seq.end() + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + let v: Vec = Vec::deserialize(deserializer)?; + v.into_iter() + .map(|e| { + Certificate::from_str(&e).map_err(|e| { + Error::custom(format!("certificate deserialization failed for {:?}", e)) + }) + }) + .collect() + } +} diff --git a/src/key_pair.rs b/src/key_pair.rs new file mode 100644 index 0000000..0b2f686 --- /dev/null +++ b/src/key_pair.rs @@ -0,0 +1,126 @@ +/* + * Copyright 2020 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::ed25519::{Keypair as Libp2pKeyPair, PublicKey, SecretKey}; +use ed25519_dalek::SignatureError; +use libp2p_core::identity::error::DecodingError; +use std::fmt; + +pub type Signature = Vec; + +/// An Ed25519 keypair. +#[derive(Clone, Debug)] +pub struct KeyPair { + pub key_pair: Libp2pKeyPair, +} + +impl KeyPair { + /// Generate a new Ed25519 keypair. + #[allow(dead_code)] + pub fn generate() -> Self { + let kp = Libp2pKeyPair::generate(); + kp.into() + } + + pub fn from_bytes(sk_bytes: impl AsMut<[u8]>) -> Result { + let sk = SecretKey::from_bytes(sk_bytes)?; + Ok(Libp2pKeyPair::from(sk).into()) + } + + /// Encode the keypair into a byte array by concatenating the bytes + /// of the secret scalar and the compressed public point/ + #[allow(dead_code)] + pub fn encode(&self) -> [u8; 64] { + self.key_pair.encode() + } + + /// Decode a keypair from the format produced by `encode`. + #[allow(dead_code)] + pub fn decode(kp: &[u8]) -> Result { + let kp = ed25519_dalek::Keypair::from_bytes(kp)?; + Ok(Self { + key_pair: kp.into(), + }) + } + + /// Get the public key of this keypair. + #[allow(dead_code)] + pub fn public_key(&self) -> PublicKey { + self.key_pair.public() + } + + /// Sign a message using the private key of this keypair. + pub fn sign(&self, msg: &[u8]) -> Vec { + self.key_pair.sign(msg) + } + + /// Verify the Ed25519 signature on a message using the public key. + pub fn verify(pk: &PublicKey, msg: &[u8], signature: &[u8]) -> Result<(), String> { + if pk.verify(msg, signature) { + return Ok(()); + } + + Err("Signature is not valid.".to_string()) + } +} + +impl From for KeyPair { + fn from(kp: Libp2pKeyPair) -> Self { + Self { key_pair: kp } + } +} + +/// Implement serde::Deserialize for KeyPair +impl<'de> serde::Deserialize<'de> for KeyPair { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + use serde::de::{Error, Unexpected, Visitor}; + + struct KeyPairVisitor; + + impl<'de> Visitor<'de> for KeyPairVisitor { + type Value = KeyPair; + + /// Error message stating what was expected + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("byte array or base58 string") + } + + /// Implement deserialization from base58 string + fn visit_str(self, s: &str) -> Result + where + E: Error, + { + bs58::decode(s) + .into_vec() + .map_err(|_| Error::invalid_value(Unexpected::Str(s), &self)) + .and_then(|v| self.visit_bytes(v.as_slice())) + } + + /// Implement deserialization from bytes + fn visit_bytes(self, b: &[u8]) -> Result + where + E: Error, + { + KeyPair::decode(b).map_err(|_| Error::invalid_value(Unexpected::Bytes(b), &self)) + } + } + + deserializer.deserialize_str(KeyPairVisitor) + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..8118e30 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,46 @@ +/* + * Copyright 2020 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#![recursion_limit = "512"] +#![warn(rust_2018_idioms)] +#![deny( + dead_code, + nonstandard_style, + unused_imports, + unused_mut, + unused_variables, + unused_unsafe, + unreachable_patterns +)] + +mod certificate; +pub mod certificate_serde; +mod key_pair; +mod misc; +mod public_key_hashable; +mod revoke; +mod trust; +mod trust_graph; +mod trust_node; + +pub(crate) use libp2p_core::identity::ed25519; + +pub use crate::certificate::Certificate; +pub use crate::key_pair::KeyPair; +pub use crate::misc::current_time; +pub use crate::public_key_hashable::PublicKeyHashable; +pub use crate::trust::Trust; +pub use crate::trust_graph::TrustGraph; diff --git a/src/misc/mod.rs b/src/misc/mod.rs new file mode 100644 index 0000000..b5ff271 --- /dev/null +++ b/src/misc/mod.rs @@ -0,0 +1,10 @@ +use std::time::{Duration, SystemTime, UNIX_EPOCH}; + +pub fn current_time() -> Duration { + Duration::from_secs( + SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs() as u64, + ) +} diff --git a/src/public_key_hashable.rs b/src/public_key_hashable.rs new file mode 100644 index 0000000..ddde308 --- /dev/null +++ b/src/public_key_hashable.rs @@ -0,0 +1,80 @@ +/* + * Copyright 2020 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::ed25519::PublicKey; + +use ref_cast::RefCast; +use serde::Deserialize; +use std::{ + fmt::{Display, Formatter}, + hash::{Hash, Hasher}, +}; + +/// Wrapper to use PublicKey in HashMap +#[derive(PartialEq, Eq, Debug, Clone, RefCast, Deserialize)] +#[repr(transparent)] +pub struct PublicKeyHashable(PublicKey); + +#[allow(clippy::derive_hash_xor_eq)] +impl Hash for PublicKeyHashable { + fn hash(&self, state: &mut H) { + state.write(&self.0.encode()); + state.finish(); + } + + fn hash_slice(data: &[Self], state: &mut H) + where + Self: Sized, + { + // TODO check for overflow + let mut bytes: Vec = Vec::with_capacity(data.len() * 32); + for d in data { + bytes.extend_from_slice(&d.0.encode()) + } + state.write(bytes.as_slice()); + state.finish(); + } +} + +impl From for PublicKeyHashable { + fn from(pk: PublicKey) -> Self { + Self(pk) + } +} + +impl Into for PublicKeyHashable { + fn into(self) -> PublicKey { + self.0 + } +} + +impl AsRef for PublicKeyHashable { + fn as_ref(&self) -> &PublicKey { + &self.0 + } +} + +impl AsRef for PublicKey { + fn as_ref(&self) -> &PublicKeyHashable { + PublicKeyHashable::ref_cast(self) + } +} + +impl Display for PublicKeyHashable { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", bs58::encode(self.0.encode()).into_string()) + } +} diff --git a/src/revoke.rs b/src/revoke.rs new file mode 100644 index 0000000..b35be0e --- /dev/null +++ b/src/revoke.rs @@ -0,0 +1,121 @@ +/* + * Copyright 2020 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::ed25519::PublicKey; +use crate::key_pair::KeyPair; +use crate::key_pair::Signature; +use crate::trust::{EXPIRATION_LEN, PK_LEN}; +use std::time::Duration; + +/// "A document" that cancels trust created before. +/// TODO delete pk from Revoke (it is already in a trust node) +#[derive(Debug, Clone)] +pub struct Revoke { + /// who is revoked + pub pk: PublicKey, + /// date when revocation was created + pub revoked_at: Duration, + /// the issuer of this revocation + pub revoked_by: PublicKey, + /// proof of this revocation + signature: Signature, +} + +impl Revoke { + #[allow(dead_code)] + fn new( + pk: PublicKey, + revoked_by: PublicKey, + revoked_at: Duration, + signature: Signature, + ) -> Self { + Self { + pk, + revoked_at, + revoked_by, + signature, + } + } + + /// Creates new revocation signed by a revoker. + #[allow(dead_code)] + pub fn create(revoker: &KeyPair, to_revoke: PublicKey, revoked_at: Duration) -> Self { + let msg = Revoke::signature_bytes(&to_revoke, revoked_at); + let signature = revoker.sign(&msg); + + Revoke::new(to_revoke, revoker.public_key(), revoked_at, signature) + } + + fn signature_bytes(pk: &PublicKey, revoked_at: Duration) -> Vec { + let mut msg = Vec::with_capacity(PK_LEN + EXPIRATION_LEN); + msg.extend_from_slice(&pk.encode()); + msg.extend_from_slice(&(revoked_at.as_secs() as u64).to_le_bytes()); + + msg + } + + /// Verifies that revocation is cryptographically correct. + pub fn verify(revoke: &Revoke) -> Result<(), String> { + let msg = Revoke::signature_bytes(&revoke.pk, revoke.revoked_at); + + if !revoke + .revoked_by + .verify(msg.as_slice(), revoke.signature.as_slice()) + { + return Err("Revoke has incorrect signature.".to_string()); + } + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + + use super::*; + + #[test] + fn test_gen_revoke_and_validate() { + let revoker = KeyPair::generate(); + let to_revoke = KeyPair::generate(); + + let duration = Duration::new(100, 0); + + let revoke = Revoke::create(&revoker, to_revoke.public_key(), duration); + + assert_eq!(Revoke::verify(&revoke).is_ok(), true); + } + + #[test] + fn test_validate_corrupted_revoke() { + let revoker = KeyPair::generate(); + let to_revoke = KeyPair::generate(); + + let duration = Duration::new(100, 0); + + let revoke = Revoke::create(&revoker, to_revoke.public_key(), duration); + + let duration2 = Duration::new(95, 0); + let corrupted_revoke = Revoke::new( + to_revoke.public_key(), + revoker.public_key(), + duration2, + revoke.signature, + ); + + assert_eq!(Revoke::verify(&corrupted_revoke).is_ok(), false); + } +} diff --git a/src/trust.rs b/src/trust.rs new file mode 100644 index 0000000..7f54f11 --- /dev/null +++ b/src/trust.rs @@ -0,0 +1,277 @@ +/* + * Copyright 2020 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::ed25519::PublicKey; +use crate::key_pair::{KeyPair, Signature}; +use derivative::Derivative; +use std::convert::TryInto; +use std::time::Duration; + +pub const SIG_LEN: usize = 64; +pub const PK_LEN: usize = 32; +pub const EXPIRATION_LEN: usize = 8; +pub const ISSUED_LEN: usize = 8; +pub const METADATA_LEN: usize = PK_LEN + EXPIRATION_LEN + ISSUED_LEN; +pub const TRUST_LEN: usize = SIG_LEN + PK_LEN + EXPIRATION_LEN + ISSUED_LEN; + +/// One element in chain of trust in a certificate. +/// TODO delete pk from Trust (it is already in a trust node) +#[derive(Clone, PartialEq, Derivative, Eq)] +#[derivative(Debug)] +pub struct Trust { + /// For whom this certificate is issued + #[derivative(Debug(format_with = "show_pubkey"))] + pub issued_for: PublicKey, + /// Expiration date of a trust. + pub expires_at: Duration, + /// Signature of a previous trust in a chain. + /// Signature is self-signed if it is a root trust. + #[derivative(Debug(format_with = "show_sig"))] + pub signature: Signature, + /// Creation time of a trust + pub issued_at: Duration, +} + +fn show_pubkey(key: &PublicKey, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + write!(f, "{}", bs58::encode(key.encode()).into_string()) +} + +fn show_sig(sig: &[u8], f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + write!(f, "{}", bs58::encode(sig).into_string()) +} + +impl Trust { + #[allow(dead_code)] + pub fn new( + issued_for: PublicKey, + expires_at: Duration, + issued_at: Duration, + signature: Signature, + ) -> Self { + Self { + issued_for, + expires_at, + issued_at, + signature, + } + } + + pub fn create( + issued_by: &KeyPair, + issued_for: PublicKey, + expires_at: Duration, + issued_at: Duration, + ) -> Self { + let msg = Self::metadata_bytes(&issued_for, expires_at, issued_at); + + let signature = issued_by.sign(&msg); + + Self { + issued_for, + expires_at, + signature, + issued_at, + } + } + + /// Verifies that authorization is cryptographically correct. + pub fn verify(trust: &Trust, issued_by: &PublicKey, cur_time: Duration) -> Result<(), String> { + if trust.expires_at < cur_time { + return Err("Trust in chain is expired.".to_string()); + } + + let msg: &[u8] = + &Self::metadata_bytes(&trust.issued_for, trust.expires_at, trust.issued_at); + + KeyPair::verify(issued_by, msg, trust.signature.as_slice())?; + + Ok(()) + } + + fn metadata_bytes(pk: &PublicKey, expires_at: Duration, issued_at: Duration) -> [u8; 48] { + let pk_encoded = pk.encode(); + let expires_at_encoded: [u8; EXPIRATION_LEN] = (expires_at.as_secs() as u64).to_le_bytes(); + let issued_at_encoded: [u8; ISSUED_LEN] = (issued_at.as_secs() as u64).to_le_bytes(); + let mut metadata = [0; METADATA_LEN]; + + metadata[..PK_LEN].clone_from_slice(&pk_encoded[..PK_LEN]); + metadata[PK_LEN..PK_LEN + EXPIRATION_LEN] + .clone_from_slice(&expires_at_encoded[0..EXPIRATION_LEN]); + metadata[PK_LEN + EXPIRATION_LEN..METADATA_LEN] + .clone_from_slice(&issued_at_encoded[0..ISSUED_LEN]); + + metadata + } + + /// Encode the trust into a byte array + #[allow(dead_code)] + pub fn encode(&self) -> Vec { + let mut vec = Vec::with_capacity(TRUST_LEN); + vec.extend_from_slice(&self.issued_for.encode()); + vec.extend_from_slice(&self.signature.as_slice()); + vec.extend_from_slice(&(self.expires_at.as_secs() as u64).to_le_bytes()); + vec.extend_from_slice(&(self.issued_at.as_secs() as u64).to_le_bytes()); + + vec + } + + /// Decode a trust from a byte array as produced by `encode`. + #[allow(dead_code)] + pub fn decode(arr: &[u8]) -> Result { + if arr.len() != TRUST_LEN { + return Err( + format!("Trust length should be 104: public key(32) + signature(64) + expiration date(8), was: {}", arr.len()), + ); + } + + let pk = PublicKey::decode(&arr[0..PK_LEN]).map_err(|err| err.to_string())?; + let signature = &arr[PK_LEN..PK_LEN + SIG_LEN]; + + let expiration_bytes = &arr[PK_LEN + SIG_LEN..PK_LEN + SIG_LEN + EXPIRATION_LEN]; + let expiration_date = u64::from_le_bytes(expiration_bytes.try_into().unwrap()); + let expiration_date = Duration::from_secs(expiration_date); + + let issued_bytes = &arr[PK_LEN + SIG_LEN + EXPIRATION_LEN..TRUST_LEN]; + let issued_date = u64::from_le_bytes(issued_bytes.try_into().unwrap()); + let issued_date = Duration::from_secs(issued_date); + + Ok(Self { + issued_for: pk, + signature: signature.to_vec(), + expires_at: expiration_date, + issued_at: issued_date, + }) + } + + fn bs58_str_to_vec(str: &str, field: &str) -> Result, String> { + bs58::decode(str).into_vec().map_err(|e| { + format!( + "Cannot decode `{}` from base58 format in the trust '{}': {}", + field, str, e + ) + }) + } + + fn str_to_duration(str: &str, field: &str) -> Result { + let secs = str.parse().map_err(|e| { + format!( + "Cannot parse `{}` field in the trust '{}': {}", + field, str, e + ) + })?; + Ok(Duration::from_secs(secs)) + } + + pub fn convert_from_strings( + issued_for: &str, + signature: &str, + expires_at: &str, + issued_at: &str, + ) -> Result { + // PublicKey + let issued_for_bytes = Self::bs58_str_to_vec(issued_for, "issued_for")?; + let issued_for = PublicKey::decode(issued_for_bytes.as_slice()).map_err(|e| { + format!( + "Cannot decode the public key: {} in the trust '{}'", + issued_for, e + ) + })?; + + // 64 bytes signature + let signature = Self::bs58_str_to_vec(signature, "signature")?; + + // Duration + let expires_at = Self::str_to_duration(expires_at, "expires_at")?; + + // Duration + let issued_at = Self::str_to_duration(issued_at, "issued_at")?; + + Ok(Trust::new(issued_for, expires_at, issued_at, signature)) + } +} + +impl ToString for Trust { + fn to_string(&self) -> String { + let issued_for = bs58::encode(self.issued_for.encode()).into_string(); + let signature = bs58::encode(self.signature.as_slice()).into_string(); + let expires_at = (self.expires_at.as_secs() as u64).to_string(); + let issued_at = (self.issued_at.as_secs() as u64).to_string(); + + format!( + "{}\n{}\n{}\n{}", + issued_for, signature, expires_at, issued_at + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_gen_revoke_and_validate() { + let truster = KeyPair::generate(); + let trusted = KeyPair::generate(); + + let current = Duration::new(100, 0); + let duration = Duration::new(1000, 0); + let issued_at = Duration::new(10, 0); + + let trust = Trust::create(&truster, trusted.public_key(), duration, issued_at); + + assert_eq!( + Trust::verify(&trust, &truster.public_key(), current).is_ok(), + true + ); + } + + #[test] + fn test_validate_corrupted_revoke() { + let truster = KeyPair::generate(); + let trusted = KeyPair::generate(); + + let current = Duration::new(1000, 0); + let issued_at = Duration::new(10, 0); + + let trust = Trust::create(&truster, trusted.public_key(), current, issued_at); + + let corrupted_duration = Duration::new(1234, 0); + let corrupted_trust = Trust::new( + trust.issued_for, + trust.expires_at, + corrupted_duration, + trust.signature, + ); + + assert!(Trust::verify(&corrupted_trust, &truster.public_key(), current).is_err()); + } + + #[test] + fn test_encode_decode() { + let truster = KeyPair::generate(); + let trusted = KeyPair::generate(); + + let current = Duration::new(1000, 0); + let issued_at = Duration::new(10, 0); + + let trust = Trust::create(&truster, trusted.public_key(), current, issued_at); + + let encoded = trust.encode(); + let decoded = Trust::decode(encoded.as_slice()).unwrap(); + + assert_eq!(trust, decoded); + } +} diff --git a/src/trust_graph.rs b/src/trust_graph.rs new file mode 100644 index 0000000..a023298 --- /dev/null +++ b/src/trust_graph.rs @@ -0,0 +1,618 @@ +/* + * Copyright 2020 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::certificate::Certificate; +use crate::ed25519::PublicKey; +use crate::public_key_hashable::PublicKeyHashable; +use crate::revoke::Revoke; +use crate::trust::Trust; +use crate::trust_node::{Auth, TrustNode}; +use std::borrow::Borrow; +use std::collections::hash_map::Entry; +use std::collections::hash_map::Entry::Occupied; +use std::collections::{HashMap, HashSet, VecDeque}; +use std::fmt::Debug; +use std::time::Duration; + +/// for simplicity, we store `n` where Weight = 1/n^2 +type Weight = u32; + +/// Graph to efficiently calculate weights of certificates and get chains of certificates. +/// TODO serialization/deserialization +/// TODO export a certificate from graph +#[allow(dead_code)] +#[derive(Debug, Default)] +pub struct TrustGraph { + // TODO abstract this into a trait with key access methods + // TODO: add docs on fields + nodes: HashMap, + root_weights: HashMap, +} + +#[allow(dead_code)] +impl TrustGraph { + pub fn new(root_weights: Vec<(PublicKey, Weight)>) -> Self { + Self { + nodes: HashMap::new(), + root_weights: root_weights + .into_iter() + .map(|(k, w)| (k.into(), w)) + .collect(), + } + } + + /// Insert new root weights + pub fn add_root_weights>(&mut self, weights: Vec<(P, Weight)>) { + self.root_weights + .extend(weights.into_iter().map(|(k, w)| (k.into(), w))) + } + + /// Get trust by public key + pub fn get(&self, pk: PublicKey) -> Option<&TrustNode> { + self.nodes.get(&pk.into()) + } + + // TODO: remove cur_time from api, leave it for tests only + /// Certificate is a chain of trusts, add this chain to graph + pub fn add(&mut self, cert: C, cur_time: Duration) -> Result<(), String> + where + C: Borrow, + { + let roots: Vec = self.root_weights.keys().cloned().map(Into::into).collect(); + // Check that certificate is valid and converges to one of the known roots + Certificate::verify(cert.borrow(), roots.as_slice(), cur_time)?; + + let mut chain = cert.borrow().chain.iter(); + let root_trust = chain.next().ok_or("empty chain")?; + let root_pk: PublicKeyHashable = root_trust.issued_for.clone().into(); + + // Insert new TrustNode for this root_pk if there wasn't one + if self.nodes.get_mut(&root_pk).is_none() { + let mut trust_node = TrustNode::new(root_trust.issued_for.clone(), cur_time); + let root_auth = Auth { + trust: root_trust.clone(), + issued_by: root_trust.issued_for.clone(), + }; + trust_node.update_auth(root_auth); + self.nodes.insert(root_pk, trust_node); + } + + // Insert remaining trusts to the graph + let mut previous_trust = root_trust; + for trust in chain { + let pk = trust.issued_for.clone().into(); + + let auth = Auth { + trust: trust.clone(), + issued_by: previous_trust.issued_for.clone(), + }; + + match self.nodes.get_mut(&pk) { + Some(trust_node) => { + trust_node.update_auth(auth); + } + None => { + let mut trust_node = TrustNode::new(root_trust.issued_for.clone(), cur_time); + trust_node.update_auth(auth); + self.nodes.insert(pk, trust_node); + } + } + + previous_trust = trust; + } + + Ok(()) + } + + /// Get the maximum weight of trust for one public key. + pub fn weight

(&self, pk: P) -> Option + where + P: Borrow, + { + if let Some(weight) = self.root_weights.get(pk.borrow().as_ref()) { + return Some(*weight); + } + + let roots: Vec = self + .root_weights + .keys() + .map(|pk| pk.clone().into()) + .collect(); + + // get all possible certificates from the given public key to all roots in the graph + let certs = self.get_all_certs(pk, roots.as_slice()); + self.certificates_weight(certs) + } + + /// Calculate weight from given certificates + /// Returns None if there is no such public key + /// or some trust between this key and a root key is revoked. + /// TODO handle non-direct revocations + pub fn certificates_weight(&self, certs: I) -> Option + where + C: Borrow, + I: IntoIterator, + { + let mut certs = certs.into_iter().peekable(); + // if there are no certificates for the given public key, there is no info about this public key + // or some elements of possible certificate chains was revoked + certs.peek()?; + + let mut weight = std::u32::MAX; + + for cert in certs { + let cert = cert.borrow(); + + let root_weight = *self + .root_weights + .get(cert.chain.first()?.issued_for.as_ref()) + // This panic shouldn't happen // TODO: why? + .expect("first trust in chain must be in root_weights"); + + // certificate weight = root weight + 1 * every other element in the chain + // (except root, so the formula is `root weight + chain length - 1`) + weight = std::cmp::min(weight, root_weight + cert.chain.len() as u32 - 1) + } + + Some(weight) + } + + /// BF search for all converging paths (chains) in the graph + /// TODO could be optimized with closure, that will calculate the weight on the fly + /// TODO or store auths to build certificates + fn bf_search_paths( + &self, + node: &TrustNode, + roots: HashSet<&PublicKeyHashable>, + ) -> Vec> { + // queue to collect all chains in the trust graph (each chain is a path in the trust graph) + let mut chains_queue: VecDeque> = VecDeque::new(); + + let node_auths: Vec = node.authorizations().cloned().collect(); + // put all auth in the queue as the first possible paths through the graph + for auth in node_auths { + chains_queue.push_back(vec![auth]); + } + + // List of all chains that converge (terminate) to known roots + let mut terminated_chains: Vec> = Vec::new(); + + while !chains_queue.is_empty() { + let cur_chain = chains_queue + .pop_front() + .expect("`chains_queue` always has at least one element"); + + let last = cur_chain + .last() + .expect("`cur_chain` always has at least one element"); + + let auths: Vec = self + .nodes + .get(&last.issued_by.clone().into()) + .expect( + "there cannot be paths without any nodes after adding verified certificates", + ) + .authorizations() + .cloned() + .collect(); + + for auth in auths { + // if there is auth, that we not visited in the current chain, copy chain and append this auth + if !cur_chain + .iter() + .any(|a| a.trust.issued_for == auth.issued_by) + { + let mut new_chain = cur_chain.clone(); + new_chain.push(auth); + chains_queue.push_back(new_chain); + } + } + + // to be considered a valid chain, the chain must: + // - end with a self-signed trust + // - that trust must converge to one of the root weights + // - there should be more than 1 trust in the chain + let self_signed = last.issued_by == last.trust.issued_for; + let converges_to_root = roots.contains(last.issued_by.as_ref()); + + if self_signed && converges_to_root && cur_chain.len() > 1 { + terminated_chains.push(cur_chain); + } + } + + terminated_chains + } + + // TODO: remove `roots` argument from api, leave it for tests and internal usage only + /// Get all possible certificates where `issued_for` will be the last element of the chain + /// and one of the destinations is the root of this chain. + pub fn get_all_certs

(&self, issued_for: P, roots: &[PublicKey]) -> Vec + where + P: Borrow, + { + // get all auths (edges) for issued public key + let issued_for_node = self.nodes.get(issued_for.borrow().as_ref()); + + let roots = roots.iter().map(|pk| pk.as_ref()); + let roots = self.root_weights.keys().chain(roots).collect(); + + match issued_for_node { + Some(node) => self + .bf_search_paths(node, roots) + .iter() + .map(|auths| { + // TODO: can avoid cloning here by returning &Certificate + let trusts: Vec = + auths.iter().map(|auth| auth.trust.clone()).rev().collect(); + Certificate::new_unverified(trusts) + }) + .filter(|c| { + // Certificate with one trust means nothing, gotta be a bug. Checking for it here. + debug_assert!( + c.chain.len() > 1, + "certificate with chain of len 1 arose: {:#?}", + c + ); + c.chain.len() > 1 + }) + .collect(), + None => Vec::new(), + } + } + + /// Mark public key as revoked. + pub fn revoke(&mut self, revoke: Revoke) -> Result<(), String> { + Revoke::verify(&revoke)?; + + let pk: PublicKeyHashable = revoke.pk.clone().into(); + + match self.nodes.entry(pk) { + Occupied(mut entry) => { + entry.get_mut().update_revoke(revoke); + Ok(()) + } + Entry::Vacant(_) => Err("There is no trust with such PublicKey".to_string()), + } + } + + /// Check information about new certificates and about revoked certificates. + /// Do it once per some time + // TODO + fn maintain() {} +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::key_pair::KeyPair; + use crate::misc::current_time; + use failure::_core::time::Duration; + + pub fn one_minute() -> Duration { + Duration::new(60, 0) + } + + fn generate_root_cert() -> (KeyPair, KeyPair, Certificate) { + let root_kp = KeyPair::generate(); + let second_kp = KeyPair::generate(); + + let cur_time = current_time(); + + ( + root_kp.clone(), + second_kp.clone(), + Certificate::issue_root( + &root_kp, + second_kp.public_key(), + cur_time.checked_add(one_minute()).unwrap(), + cur_time, + ), + ) + } + + fn generate_cert_with( + len: usize, + // Map of index to keypair. These key pairs will be used in trust chains at the given indexes + keys: HashMap, + expires_at: Duration, + issued_at: Duration, + ) -> (Vec, Certificate) { + assert!(len > 2); + + let root_kp = KeyPair::generate(); + let second_kp = KeyPair::generate(); + + let mut cert = + Certificate::issue_root(&root_kp, second_kp.public_key(), expires_at, issued_at); + + let mut key_pairs = vec![root_kp, second_kp]; + + for idx in 2..len { + let kp = keys.get(&idx).unwrap_or(&KeyPair::generate()).clone(); + let previous_kp = &key_pairs[idx - 1]; + cert = Certificate::issue( + &previous_kp, + kp.public_key(), + &cert, + expires_at, + // TODO: why `issued_at = issued_at - 60 seconds`? + issued_at.checked_sub(Duration::from_secs(60)).unwrap(), + current_time(), + ) + .unwrap(); + key_pairs.push(kp); + } + + (key_pairs, cert) + } + + fn generate_cert_with_len( + len: usize, + keys: HashMap, + ) -> (Vec, Certificate) { + let cur_time = current_time(); + let far_future = cur_time.checked_add(one_minute()).unwrap(); + + generate_cert_with(len, keys, far_future, cur_time) + } + + #[test] + fn test_add_cert_without_trusted_root() { + let (_, _, cert) = generate_root_cert(); + + let cur_time = current_time(); + + let mut graph = TrustGraph::default(); + let addition = graph.add(cert, cur_time); + assert_eq!(addition.is_ok(), false); + } + + #[test] + fn test_add_cert() { + let (root, _, cert) = generate_root_cert(); + + let mut graph = TrustGraph::default(); + graph.root_weights.insert(root.key_pair.public().into(), 0); + + let addition = graph.add(cert, current_time()); + assert_eq!(addition.is_ok(), true); + } + + #[test] + fn test_add_certs_with_same_trusts_and_different_expirations() { + let cur_time = current_time(); + let far_future = cur_time + Duration::from_secs(10); + let far_far_future = cur_time + Duration::from_secs(900); + let key_pair1 = KeyPair::generate(); + let key_pair2 = KeyPair::generate(); + + // Use key_pair1 and key_pair2 for 5th and 6th trust in the cert chain + let mut chain_keys = HashMap::new(); + chain_keys.insert(5, key_pair1.clone()); + chain_keys.insert(6, key_pair2.clone()); + + let (key_pairs1, cert1) = generate_cert_with(10, chain_keys, far_future * 2, far_future); + + // Use key_pair1 and key_pair2 for 7th and 8th trust in the cert chain + let mut chain_keys = HashMap::new(); + chain_keys.insert(7, key_pair1.clone()); + chain_keys.insert(8, key_pair2.clone()); + + let (key_pairs2, cert2) = + generate_cert_with(10, chain_keys, far_far_future * 2, far_far_future); + + let mut graph = TrustGraph::default(); + let root1_pk = key_pairs1[0].public_key(); + let root2_pk = key_pairs2[0].public_key(); + graph.root_weights.insert(root1_pk.into(), 1); + graph.root_weights.insert(root2_pk.into(), 0); + graph.add(cert1, cur_time).unwrap(); + + let node2 = graph.get(key_pair2.public_key()).unwrap(); + let auth_by_kp1 = node2 + .authorizations() + .find(|a| a.issued_by == key_pair1.public_key()) + .unwrap(); + + assert_eq!(auth_by_kp1.trust.expires_at, far_future * 2); + + graph.add(cert2, cur_time).unwrap(); + + let node2 = graph.get(key_pair2.public_key()).unwrap(); + let auth_by_kp1 = node2 + .authorizations() + .find(|a| a.issued_by == key_pair1.public_key()) + .unwrap(); + + assert_eq!(auth_by_kp1.trust.expires_at, far_far_future * 2); + } + + #[test] + fn test_one_cert_in_graph() { + let (key_pairs, cert1) = generate_cert_with_len(10, HashMap::new()); + let last_trust = cert1.chain[9].clone(); + + let mut graph = TrustGraph::default(); + + let root_pk = key_pairs[0].public_key(); + graph.root_weights.insert(root_pk.into(), 1); + + graph.add(cert1, current_time()).unwrap(); + + let w1 = graph.weight(key_pairs[0].public_key()).unwrap(); + assert_eq!(w1, 1); + + let w2 = graph.weight(key_pairs[1].public_key()).unwrap(); + assert_eq!(w2, 2); + + let w3 = graph.weight(key_pairs[9].public_key()).unwrap(); + assert_eq!(w3, 10); + + let node = graph.get(key_pairs[9].public_key()).unwrap(); + let auths: Vec<&Auth> = node.authorizations().collect(); + + assert_eq!(auths.len(), 1); + assert_eq!(auths[0].trust, last_trust); + } + + #[test] + fn test_cycles_in_graph() { + let key_pair1 = KeyPair::generate(); + let key_pair2 = KeyPair::generate(); + let key_pair3 = KeyPair::generate(); + + let mut chain_keys = HashMap::new(); + chain_keys.insert(3, key_pair1.clone()); + chain_keys.insert(5, key_pair2.clone()); + chain_keys.insert(7, key_pair3.clone()); + + let (key_pairs1, cert1) = generate_cert_with_len(10, chain_keys); + + let mut chain_keys = HashMap::new(); + chain_keys.insert(7, key_pair1.clone()); + chain_keys.insert(6, key_pair2.clone()); + chain_keys.insert(5, key_pair3.clone()); + + let (key_pairs2, cert2) = generate_cert_with_len(10, chain_keys); + + let mut graph = TrustGraph::default(); + let root1_pk = key_pairs1[0].public_key(); + let root2_pk = key_pairs2[0].public_key(); + graph.root_weights.insert(root1_pk.into(), 1); + graph.root_weights.insert(root2_pk.into(), 0); + + let last_pk1 = cert1.chain[9].issued_for.clone(); + let last_pk2 = cert2.chain[9].issued_for.clone(); + + graph.add(cert1, current_time()).unwrap(); + graph.add(cert2, current_time()).unwrap(); + + let revoke1 = Revoke::create(&key_pairs1[3], key_pairs1[4].public_key(), current_time()); + graph.revoke(revoke1).unwrap(); + let revoke2 = Revoke::create(&key_pairs2[5], key_pairs2[6].public_key(), current_time()); + graph.revoke(revoke2).unwrap(); + + let w1 = graph.weight(key_pair1.public_key()).unwrap(); + // all upper trusts are revoked for this public key + let w2 = graph.weight(key_pair2.public_key()); + let w3 = graph.weight(key_pair3.public_key()).unwrap(); + let w_last1 = graph.weight(last_pk1).unwrap(); + let w_last2 = graph.weight(last_pk2).unwrap(); + + assert_eq!(w1, 4); + assert_eq!(w2.is_none(), true); + assert_eq!(w3, 5); + assert_eq!(w_last1, 7); + assert_eq!(w_last2, 6); + } + + #[test] + fn test_get_one_cert() { + let (key_pairs, cert) = generate_cert_with_len(5, HashMap::new()); + + let mut graph = TrustGraph::default(); + let root1_pk = key_pairs[0].public_key(); + graph.root_weights.insert(root1_pk.clone().into(), 1); + + graph.add(cert.clone(), current_time()).unwrap(); + + let certs = graph.get_all_certs(key_pairs.last().unwrap().public_key(), &[root1_pk]); + + assert_eq!(certs.len(), 1); + assert_eq!(certs[0], cert); + } + + #[test] + fn test_chain_from_root_to_another_root() { + let (_, cert) = generate_cert_with_len(6, HashMap::new()); + + let mut graph = TrustGraph::default(); + // add first and last trusts as roots + graph + .root_weights + .insert(cert.chain[0].clone().issued_for.into(), 1); + graph + .root_weights + .insert(cert.chain[3].clone().issued_for.into(), 1); + graph + .root_weights + .insert(cert.chain[5].clone().issued_for.into(), 1); + + graph.add(cert.clone(), current_time()).unwrap(); + + let t = cert.chain[5].clone(); + let certs = graph.get_all_certs(t.issued_for, &[]); + + assert_eq!(certs.len(), 1); + } + + #[test] + fn test_find_certs() { + let key_pair1 = KeyPair::generate(); + let key_pair2 = KeyPair::generate(); + let key_pair3 = KeyPair::generate(); + + let mut chain_keys = HashMap::new(); + chain_keys.insert(2, key_pair1.clone()); + chain_keys.insert(3, key_pair2.clone()); + chain_keys.insert(4, key_pair3.clone()); + + let (key_pairs1, cert1) = generate_cert_with_len(5, chain_keys); + + let mut chain_keys = HashMap::new(); + chain_keys.insert(4, key_pair1.clone()); + chain_keys.insert(3, key_pair2.clone()); + chain_keys.insert(2, key_pair3.clone()); + + let (key_pairs2, cert2) = generate_cert_with_len(5, chain_keys); + + let mut chain_keys = HashMap::new(); + chain_keys.insert(3, key_pair1.clone()); + chain_keys.insert(4, key_pair2.clone()); + chain_keys.insert(2, key_pair3.clone()); + + let (key_pairs3, cert3) = generate_cert_with_len(5, chain_keys); + + let mut graph = TrustGraph::default(); + let root1_pk = key_pairs1[0].public_key(); + let root2_pk = key_pairs2[0].public_key(); + let root3_pk = key_pairs3[0].public_key(); + graph.root_weights.insert(root1_pk.clone().into(), 1); + graph.root_weights.insert(root2_pk.clone().into(), 0); + graph.root_weights.insert(root3_pk.clone().into(), 0); + + graph.add(cert1, current_time()).unwrap(); + graph.add(cert2, current_time()).unwrap(); + graph.add(cert3, current_time()).unwrap(); + + let roots_values = [root1_pk, root2_pk, root3_pk]; + + let certs1 = graph.get_all_certs(key_pair1.public_key(), &roots_values); + let lenghts1: Vec = certs1.iter().map(|c| c.chain.len()).collect(); + let check_lenghts1: Vec = vec![3, 4, 4, 5, 5]; + assert_eq!(lenghts1, check_lenghts1); + + let certs2 = graph.get_all_certs(key_pair2.public_key(), &roots_values); + let lenghts2: Vec = certs2.iter().map(|c| c.chain.len()).collect(); + let check_lenghts2: Vec = vec![4, 4, 4, 5, 5]; + assert_eq!(lenghts2, check_lenghts2); + + let certs3 = graph.get_all_certs(key_pair3.public_key(), &roots_values); + let lenghts3: Vec = certs3.iter().map(|c| c.chain.len()).collect(); + let check_lenghts3: Vec = vec![3, 3, 5]; + assert_eq!(lenghts3, check_lenghts3); + } +} diff --git a/src/trust_node.rs b/src/trust_node.rs new file mode 100644 index 0000000..4850dfc --- /dev/null +++ b/src/trust_node.rs @@ -0,0 +1,202 @@ +/* + * Copyright 2020 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::ed25519::PublicKey; +use crate::public_key_hashable::PublicKeyHashable; +use crate::revoke::Revoke; +use crate::trust::Trust; +use failure::_core::time::Duration; +use std::collections::HashMap; + +#[derive(Debug, Clone)] +enum TrustRelation { + Auth(Auth), + Revoke(Revoke), +} + +impl TrustRelation { + /// Returns timestamp of when this relation was created + pub fn issued_at(&self) -> Duration { + match self { + TrustRelation::Auth(auth) => auth.trust.issued_at, + TrustRelation::Revoke(revoke) => revoke.revoked_at, + } + } + + /// Returns public key of the creator of this relation + pub fn issued_by(&self) -> &PublicKey { + match self { + TrustRelation::Auth(auth) => &auth.issued_by, + TrustRelation::Revoke(revoke) => &revoke.revoked_by, + } + } +} + +/// Represents who give a certificate +#[derive(Debug, Clone)] +pub struct Auth { + /// proof of this authorization + pub trust: Trust, + /// the issuer of this authorization + pub issued_by: PublicKey, +} + +/// An element of trust graph that store relations (trust or revoke) +/// that given by some owners of public keys. +#[derive(Debug)] +pub struct TrustNode { + /// identity key of this element + pub pk: PublicKey, + + /// one public key could be authorized or revoked by multiple certificates + trust_relations: HashMap, + + /// for maintain + pub verified_at: Duration, +} + +#[allow(dead_code)] +impl TrustNode { + pub fn new(pk: PublicKey, verified_at: Duration) -> Self { + Self { + pk, + trust_relations: HashMap::new(), + verified_at, + } + } + + pub fn get_auth(&self, pk: PublicKey) -> Option { + match self.trust_relations.get(&pk.into()) { + Some(TrustRelation::Auth(auth)) => Some(auth.clone()), + _ => None, + } + } + + pub fn get_revoke(&self, pk: PublicKey) -> Option { + match self.trust_relations.get(&pk.into()) { + Some(TrustRelation::Revoke(rev)) => Some(rev.clone()), + _ => None, + } + } + + pub fn authorizations(&self) -> impl Iterator + '_ { + self.trust_relations.values().filter_map(|tr| { + if let TrustRelation::Auth(auth) = tr { + Some(auth) + } else { + None + } + }) + } + + pub fn revocations(&self) -> impl Iterator + '_ { + self.trust_relations.values().filter_map(|tr| { + if let TrustRelation::Revoke(revoke) = tr { + Some(revoke) + } else { + None + } + }) + } + + /// Adds authorization. If the trust node already has this authorization, + /// add auth with later expiration date. + pub fn update_auth(&mut self, auth: Auth) { + self.update_relation(TrustRelation::Auth(auth)); + } + + // insert new trust relation, ignore if there is another one with same public key + fn insert(&mut self, pk: PublicKeyHashable, tr: TrustRelation) { + self.trust_relations.insert(pk, tr); + } + + fn update_relation(&mut self, relation: TrustRelation) { + let issued_by = relation.issued_by().as_ref(); + + match self.trust_relations.get(issued_by) { + Some(TrustRelation::Auth(auth)) => { + if auth.trust.issued_at < relation.issued_at() { + self.insert(issued_by.clone(), relation) + } + } + Some(TrustRelation::Revoke(existed_revoke)) => { + if existed_revoke.revoked_at < relation.issued_at() { + self.insert(issued_by.clone(), relation) + } + } + None => self.insert(issued_by.clone(), relation), + }; + } + + pub fn update_revoke(&mut self, revoke: Revoke) { + self.update_relation(TrustRelation::Revoke(revoke)); + } +} + +#[cfg(test)] +mod tests { + use std::time::Duration; + + use crate::key_pair::KeyPair; + + use super::*; + + #[test] + fn test_auth_and_revoke_trust_node() { + let kp = KeyPair::generate(); + + let now = Duration::new(50, 0); + let past = Duration::new(5, 0); + let future = Duration::new(500, 0); + + let mut trust_node = TrustNode { + pk: kp.public_key(), + trust_relations: HashMap::new(), + verified_at: now, + }; + + let truster = KeyPair::generate(); + + let revoke = Revoke::create(&truster, kp.public_key(), now); + + trust_node.update_revoke(revoke); + + assert!(trust_node.get_revoke(truster.public_key()).is_some()); + + let old_trust = Trust::create(&truster, kp.public_key(), Duration::new(60, 0), past); + + let old_auth = Auth { + trust: old_trust, + issued_by: truster.public_key(), + }; + + trust_node.update_auth(old_auth); + + assert!(trust_node.get_revoke(truster.public_key()).is_some()); + assert!(trust_node.get_auth(truster.public_key()).is_none()); + + let trust = Trust::create(&truster, kp.public_key(), Duration::new(60, 0), future); + let auth = Auth { + trust, + issued_by: truster.public_key(), + }; + + trust_node.update_auth(auth); + + assert!(trust_node.get_auth(truster.public_key()).is_some()); + assert!(trust_node.get_revoke(truster.public_key()).is_none()); + } +}