diff --git a/.travis.yml b/.travis.yml index 74d1c30..df52c66 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,3 +9,7 @@ rust: matrix: allow_failures: - rust: nightly + +script: + - cargo build --verbose --all-features + - cargo test --verbose --all-features diff --git a/Cargo.lock b/Cargo.lock index 9998766..9f1694a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,12 +1,18 @@ -[root] -name = "rusty_secrets" -version = "0.0.3" +[[package]] +name = "aho-corasick" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "merkle_sigs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "base64" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -14,189 +20,332 @@ name = "bitflags" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "byteorder" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cc" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "coco" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "conv" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "custom_derive" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "either" -version = "1.1.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "futures" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "gcc" -version = "0.3.51" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "lamport_sigs" -version = "0.3.0" +name = "env_logger" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "lazy_static" -version = "0.2.8" +name = "error-chain" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "libc" -version = "0.2.29" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "magenta" -version = "0.1.1" +name = "flate2" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "magenta-sys" -version = "0.1.1" +name = "fuchsia-zircon" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "merkle" -version = "1.3.0" +name = "gcc" +version = "0.3.54" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "itertools" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "protobuf 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lamport_sigs" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lazy_static" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.33" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "log" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "memchr" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "merkle" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "protobuf 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "merkle_sigs" -version = "1.2.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lamport_sigs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "merkle 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lamport_sigs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "merkle 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "miniz-sys" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num_cpus" -version = "1.6.2" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "protobuf" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "rand" -version = "0.3.16" +name = "quickcheck" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", - "magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rayon" -version = "0.7.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rayon-core 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rayon-core" -version = "1.2.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "regex" +version = "0.1.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "ring" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "rustc-serialize" -version = "0.3.24" +name = "rusty_secrets" +version = "0.0.3" +dependencies = [ + "base64 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "flate2 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "merkle_sigs 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "quickcheck 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "safemem" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "scopeguard" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "thread-id" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thread_local" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "untrusted" -version = "0.5.0" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "utf8-ranges" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-build" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] +"checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66" +"checksum base64 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "229d032f1a99302697f10b27167ae6d03d49d032e6a8e2550e8d3fc13356d2b4" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" +"checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" +"checksum cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a9b13a57efd6b30ecd6598ebdb302cca617930b5470647570468a65d12ef9719" "checksum coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c06169f5beb7e31c7c67ebf5540b8b472d23e3eade3b2ec7d1f5b504a85f91bd" -"checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299" -"checksum custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9" -"checksum either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18785c1ba806c258137c937e44ada9ee7e69a37e3c72077542cd2f069d78562a" -"checksum futures 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4b63a4792d4f8f686defe3b39b92127fea6344de5d38202b2ee5a11bbbf29d6a" -"checksum gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)" = "120d07f202dcc3f72859422563522b66fe6463a4c513df062874daad05f85f0a" -"checksum lamport_sigs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2169eee511fb4b2af1d9581f74d9503b5a86e4dbfa52ca1f5ee0d1193bf1d913" -"checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf" -"checksum libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)" = "8a014d9226c2cc402676fbe9ea2e15dd5222cd1dd57f576b5b283178c944a264" -"checksum magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf0336886480e671965f794bc9b6fce88503563013d1bfb7a502c81fe3ac527" -"checksum magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40d014c7011ac470ae28e2f76a02bfea4a8480f73e701353b49ad7a8d75f4699" -"checksum merkle 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "204bbb6953e7cc6c2cec3f63e108f0d61311a3dab33d33582b1f6f4d4ae6f992" -"checksum merkle_sigs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b446a57d9a060a9db764b6c6bd44bf79e46c512733ed9b6c23206e74394d3255" -"checksum num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aec53c34f2d0247c5ca5d32cca1478762f301740468ee9ee6dcb7a0dd7a0c584" -"checksum protobuf 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "568a15e4d572d9a5e63ae3a55f84328c984842887db179b40b4cc6a608bac6a4" -"checksum rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "eb250fd207a4729c976794d03db689c9be1d634ab5a1c9da9492a13d8fecbcdf" -"checksum rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a77c51c07654ddd93f6cb543c7a849863b03abc7e82591afda6dc8ad4ac3ac4a" -"checksum rayon-core 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7febc28567082c345f10cddc3612c6ea020fc3297a1977d472cf9fdb73e6e493" -"checksum ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2a6dc7fc06a05e6de183c5b97058582e9da2de0c136eafe49609769c507724" -"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" -"checksum scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c79eb2c3ac4bc2507cda80e7f3ac5b88bd8eae4c0914d5663e6a8933994be918" -"checksum untrusted 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6b65243989ef6aacd9c0d6bd2b822765c3361d8ed352185a6f3a41f3a718c673" +"checksum either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "740178ddf48b1a9e878e6d6509a1442a2d42fd2928aae8e7a6f8a36fb01981b3" +"checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f" +"checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" +"checksum flate2 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)" = "e6234dd4468ae5d1e2dbb06fe2b058696fdc50a339c68a393aefbf00bc81e423" +"checksum fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f6c0581a4e363262e52b87f59ee2afe3415361c6ec35e665924eb08afe8ff159" +"checksum fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "43f3795b4bae048dc6123a6b972cadde2e676f9ded08aef6bb77f5f157684a82" +"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" +"checksum itertools 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "99f3f75d7cf195a7eedb0611efe8684b55c6c7264afe3d8bc00b704f061c0fdf" +"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +"checksum lamport_sigs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5dff26ae558be16afda65815c847447c81eede19c639982e49e33bd15973d857" +"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" +"checksum libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "5ba3df4dcb460b9dfbd070d41c94c19209620c191b0340b929ce748a2bcd42d2" +"checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" +"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20" +"checksum merkle 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6311caa1c5c71548021dfc5f6113fca485d453185fdc44da92bafe266f6a5fe" +"checksum merkle_sigs 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94367864019d3b781c28c67d0a7057da0df498525982869c47ecfd73ece29f26" +"checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4" +"checksum num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "514f0d73e64be53ff320680ca671b64fe3fb91da01e1ae2ddc99eb51d453b20d" +"checksum protobuf 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "99c7a6694a7896f7c039bc20a6947b83781b019d7d40df77ae069cd2a432e4a7" +"checksum quickcheck 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "02c2411d418cea2364325b18a205664f9ef8252e06b2e911db97c0b0d98b1406" +"checksum rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)" = "6475140dfd8655aeb72e1fd4b7a1cc1c202be65d71669476e392fe62532b9edd" +"checksum rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b614fe08b6665cb9a231d07ac1364b0ef3cb3698f1239ee0c4c3a88a524f54c8" +"checksum rayon-core 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e64b609139d83da75902f88fd6c01820046840a18471e4dfcd5ac7c0f46bea53" +"checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f" +"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957" +"checksum ring 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6f7d28b30a72c01b458428e0ae988d4149c20d902346902be881e3edc4bb325c" +"checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" +"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" +"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" +"checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5" +"checksum untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f392d7819dbe58833e26872f5f6f0d68b7bbbe90fc3667e98731c4a15ad9a7ae" +"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f" +"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" +"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/Cargo.toml b/Cargo.toml index 8c5bb20..6dad657 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,10 +8,38 @@ license = "BSD-3-Clause" readme = "README.md" build = "build.rs" -[dependencies] -rustc-serialize = "^0.3.18" -rand = "^0.3.14" -ring = "^0.11.0" -merkle_sigs = "^1.2.1" -protobuf = "^1.2.0" +[features] +default = [] +dss = [] +[dependencies] +base64 = "0.9.0" +rand = "^0.3" +ring = "^0.12" +merkle_sigs = "^1.4" +protobuf = "^1.4" + +[dependencies.error-chain] +version = "0.11.0" +default-features = false + +[dev-dependencies] +itertools = "^0.7" +quickcheck = "^0.4" +flate2 = "^0.2" + +[profile.bench] +opt-level = 3 +debug = false +rpath = false +lto = true +debug-assertions = false +codegen-units = 1 + +[profile.release] +opt-level = 3 +debug = false +rpath = false +lto = true +debug-assertions = false +codegen-units = 1 diff --git a/benches/resources/1KB.txt b/benches/resources/1KB.txt new file mode 100644 index 0000000..685e335 --- /dev/null +++ b/benches/resources/1KB.txt @@ -0,0 +1 @@ +Privacy isn't about something to hide. Privacy is about something to protect. That's who you are. That's what you believe in, that's who you want to become. Privacy is the right to the self. Privacy is what gives you the ability to share with the world who you are, on your own terms, for them to understand what you're trying to be. And to protect for yourself the parts of you that you're not sure about, that you're still experimenting with. If we don't have privacy, what we're losing is the ability to make mistakes. We're losing the ability to be ourselves. Privacy is the fountainhead of all other rights. Freedom of speech doesn't have a lot of meaning if you can't have a quiet space. . . . to decide what it is that you actually wanna say. Freedom of religion doesn't mean that if you can't figure out what you actually believe without being influenced by the criticisms and sort of outside direction and peer pressure of others. And it goes on and on and on. But privacy is baked into our language, our core concepts of government and self in every way . . . without privacy, you won't have anything for yourself. So when people say that to me, I say back arguing that you don't have privacy because you have nothing to hide is like arguing that you don't care about free speech because you have nothing to say. diff --git a/benches/shared.rs b/benches/shared.rs new file mode 100644 index 0000000..96dbc41 --- /dev/null +++ b/benches/shared.rs @@ -0,0 +1,5 @@ +#![cfg(test)] + +pub fn secret_1kb() -> &'static [u8] { + include_bytes!("resources/1KB.txt") +} diff --git a/benches/ss1.rs b/benches/ss1.rs new file mode 100644 index 0000000..601e92f --- /dev/null +++ b/benches/ss1.rs @@ -0,0 +1,51 @@ +#![cfg(test)] +#![feature(test)] + +extern crate rusty_secrets; +extern crate test; + +mod shared; + +mod ss1 { + + use rusty_secrets::dss::ss1; + use test::{black_box, Bencher}; + use shared; + + macro_rules! bench_generate { + ($name:ident, $k:expr, $n:expr, $secret:ident) => ( + #[bench] + fn $name(b: &mut Bencher) { + let secret = shared::$secret(); + + b.iter(move || { + let shares = ss1::split_secret($k, $n, &secret, ss1::Reproducibility::reproducible(), &None).unwrap(); + black_box(shares); + }); + } + ) + } + + macro_rules! bench_recover { + ($name:ident, $k:expr, $n:expr, $secret:ident) => ( + #[bench] + fn $name(b: &mut Bencher) { + let secret = shared::$secret(); + let all_shares = ss1::split_secret($k, $n, &secret, ss1::Reproducibility::reproducible(), &None).unwrap(); + let shares = &all_shares.into_iter().take($k).collect::>().clone(); + + b.iter(|| { + let result = ss1::recover_secret(&shares.to_vec()).unwrap(); + black_box(result); + }); + } + ) + } + + bench_generate!(generate_1kb_3_5, 3, 5, secret_1kb); + bench_recover!(recover_1kb_3_5, 3, 5, secret_1kb); + + bench_generate!(generate_1kb_10_25, 10, 25, secret_1kb); + bench_recover!(recover_1kb_10_25, 10, 25, secret_1kb); + +} diff --git a/benches/sss.rs b/benches/sss.rs new file mode 100644 index 0000000..b48b6aa --- /dev/null +++ b/benches/sss.rs @@ -0,0 +1,57 @@ +#![cfg(test)] +#![feature(test)] + +extern crate rusty_secrets; +extern crate test; + +mod shared; + +mod sss { + + use test::{black_box, Bencher}; + use rusty_secrets::sss; + use shared; + + macro_rules! bench_generate { + ($name:ident, $k:expr, $n:expr, $secret:ident, $signed:expr) => ( + #[bench] + fn $name(b: &mut Bencher) { + let secret = shared::$secret(); + + b.iter(move || { + let shares = sss::split_secret($k, $n, secret, $signed).unwrap(); + black_box(shares); + }); + } + ) + } + + macro_rules! bench_recover { + ($name:ident, $k:expr, $n:expr, $secret:ident, $signed:expr) => ( + #[bench] + fn $name(b: &mut Bencher) { + let secret = shared::$secret(); + let all_shares = sss::split_secret($k, $n, &secret, $signed).unwrap(); + let shares = all_shares.into_iter().take($k).collect::>(); + + b.iter(|| { + let result = sss::recover_secret(&shares, $signed).unwrap(); + black_box(result); + }); + } + ) + } + + bench_generate!(generate_1kb_3_5, 3, 5, secret_1kb, false); + bench_recover!(recover_1kb_3_5, 3, 5, secret_1kb, false); + + bench_generate!(generate_1kb_3_5_signed, 3, 5, secret_1kb, true); + bench_recover!(recover_1kb_3_5_signed, 3, 5, secret_1kb, true); + + bench_generate!(generate_1kb_10_25, 10, 25, secret_1kb, false); + bench_recover!(recover_1kb_10_25, 10, 25, secret_1kb, false); + + bench_generate!(generate_1kb_10_25_signed, 10, 25, secret_1kb, true); + bench_recover!(recover_1kb_10_25_signed, 10, 25, secret_1kb, true); + +} diff --git a/benches/thss.rs b/benches/thss.rs new file mode 100644 index 0000000..95dc79c --- /dev/null +++ b/benches/thss.rs @@ -0,0 +1,51 @@ +#![cfg(test)] +#![feature(test)] + +extern crate rusty_secrets; +extern crate test; + +mod shared; + +mod thss { + + use rusty_secrets::dss::thss; + use test::{black_box, Bencher}; + use shared; + + macro_rules! bench_generate { + ($name:ident, $k:expr, $n:expr, $secret:ident) => ( + #[bench] + fn $name(b: &mut Bencher) { + let secret = shared::$secret(); + + b.iter(move || { + let shares = thss::split_secret($k, $n, &secret, &None).unwrap(); + black_box(shares); + }); + } + ) + } + + macro_rules! bench_recover { + ($name:ident, $k:expr, $n:expr, $secret:ident) => ( + #[bench] + fn $name(b: &mut Bencher) { + let secret = shared::$secret(); + let all_shares = thss::split_secret($k, $n, &secret, &None).unwrap(); + let shares = &all_shares.into_iter().take($k).collect::>().clone(); + + b.iter(|| { + let result = thss::recover_secret(&shares.to_vec()).unwrap(); + black_box(result); + }); + } + ) + } + + bench_generate!(generate_1kb_3_5, 3, 5, secret_1kb); + bench_recover!(recover_1kb_3_5, 3, 5, secret_1kb); + + bench_generate!(generate_1kb_10_25, 10, 25, secret_1kb); + bench_recover!(recover_1kb_10_25, 10, 25, secret_1kb); + +} diff --git a/benches/wrapped_secrets.rs b/benches/wrapped_secrets.rs new file mode 100644 index 0000000..627f376 --- /dev/null +++ b/benches/wrapped_secrets.rs @@ -0,0 +1,57 @@ +#![cfg(test)] +#![feature(test)] + +extern crate rusty_secrets; +extern crate test; + +mod shared; + +mod wrapped_secrets { + + use test::{black_box, Bencher}; + use rusty_secrets::wrapped_secrets; + use shared; + + macro_rules! bench_generate { + ($name:ident, $k:expr, $n:expr, $secret:ident, $signed:expr) => ( + #[bench] + fn $name(b: &mut Bencher) { + let secret = shared::$secret(); + + b.iter(move || { + let shares = wrapped_secrets::split_secret($k, $n, secret, None, $signed).unwrap(); + black_box(shares); + }); + } + ) + } + + macro_rules! bench_recover { + ($name:ident, $k:expr, $n:expr, $secret:ident, $signed:expr) => ( + #[bench] + fn $name(b: &mut Bencher) { + let secret = shared::$secret(); + let all_shares = wrapped_secrets::split_secret($k, $n, &secret, None, $signed).unwrap(); + let shares = all_shares.into_iter().take($k).collect::>(); + + b.iter(|| { + let result = wrapped_secrets::recover_secret(&shares, $signed).unwrap(); + black_box(result); + }); + } + ) + } + + bench_generate!(generate_1kb_3_5, 3, 5, secret_1kb, false); + bench_recover!(recover_1kb_3_5, 3, 5, secret_1kb, false); + + bench_generate!(generate_1kb_3_5_signed, 3, 5, secret_1kb, true); + bench_recover!(recover_1kb_3_5_signed, 3, 5, secret_1kb, true); + + bench_generate!(generate_1kb_10_25, 10, 25, secret_1kb, false); + bench_recover!(recover_1kb_10_25, 10, 25, secret_1kb, false); + + bench_generate!(generate_1kb_10_25_signed, 10, 25, secret_1kb, true); + bench_recover!(recover_1kb_10_25_signed, 10, 25, secret_1kb, true); + +} diff --git a/build.rs b/build.rs index ccdf49a..f1488f4 100644 --- a/build.rs +++ b/build.rs @@ -17,38 +17,38 @@ fn mask(bit: u8) -> u8 { /// of the polynomial division with POLY as divisor #[inline] fn xtimes(poly: u8) -> u8 { - (poly << 1) ^ (mask(poly >> 7) & POLY) + (poly << 1) ^ (mask(poly >> 7) & POLY) } struct Tables { - exp: [u8; 256], - log: [u8; 256], + exp: [u8; 256], + log: [u8; 256], } fn generate_tables(mut file: &File) { let mut tabs = Tables { - exp: [0; 256], - log: [0; 256], + exp: [0; 256], + log: [0; 256], }; let mut tmp = 1; for power in 0..255usize { - tabs.exp[power] = tmp; - tabs.log[tmp as usize] = power as u8; - tmp = xtimes(tmp); + tabs.exp[power] = tmp; + tabs.log[tmp as usize] = power as u8; + tmp = xtimes(tmp); } tabs.exp[255] = 1; match write!(file, "{}", tabs) { Ok(()) => {} - Err(_) => panic!("Could not format the table. Aborting build.") + Err(_) => panic!("Could not format the table. Aborting build."), }; } fn farray(array: [u8; 256], f: &mut fmt::Formatter) -> fmt::Result { for (index, value) in array.into_iter().enumerate() { try!(write!(f, "{}", value)); - if index != array.len()-1 { + if index != array.len() - 1 { try!(write!(f, ",")); } } @@ -75,12 +75,15 @@ fn main() { let mut f = File::create(&dest).unwrap(); - write!(f, "pub struct Tables {{ - pub exp: [u8; 256], - pub log: [u8; 256] -}} - -pub static TABLES: Tables = "); + write!( + f, + "pub struct Tables {{ \ + pub exp: [u8; 256], \ + pub log: [u8; 256] \ + }} \ + \ + pub static TABLES: Tables = " + ); generate_tables(&f); } diff --git a/fuzz/.gitignore b/fuzz/.gitignore new file mode 100644 index 0000000..572e03b --- /dev/null +++ b/fuzz/.gitignore @@ -0,0 +1,4 @@ + +target +corpus +artifacts diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock new file mode 100644 index 0000000..1bf5966 --- /dev/null +++ b/fuzz/Cargo.lock @@ -0,0 +1,304 @@ +[root] +name = "rusty_secrets-fuzz" +version = "0.0.1" +dependencies = [ + "arbitrary 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libfuzzer-sys 0.1.0 (git+https://github.com/rust-fuzz/libfuzzer-sys.git)", + "rusty_secrets 0.0.3", +] + +[[package]] +name = "arbitrary" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bitflags" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "block-buffer" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "byte-tools" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "coco" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "conv" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "custom_derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "digest" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "generic-array 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "either" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "error-chain" +version = "0.11.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "gcc" +version = "0.3.53" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "generic-array" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nodrop 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "typenum 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lamport_sigs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lazy_static" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libfuzzer-sys" +version = "0.1.0" +source = "git+https://github.com/rust-fuzz/libfuzzer-sys.git#67f73995f183099b2c8a736bc95b07d8b5903afe" +dependencies = [ + "arbitrary 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "magenta" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "magenta-sys" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "merkle" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "protobuf 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "merkle_sigs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lamport_sigs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "merkle 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "nodrop" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num_cpus" +version = "1.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "odds" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "protobuf" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rand" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", + "magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rayon" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rayon-core 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rayon-core" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ring" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc-serialize" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rusty_secrets" +version = "0.0.3" +dependencies = [ + "digest 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.11.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)", + "merkle_sigs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "sha3 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "scopeguard" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "sha3" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-buffer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "typenum" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "untrusted" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum arbitrary 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "baa5f4eaa3a3603a0d83861560ab55dfa6c8dd094b05604e5d006b41ffaeb1d3" +"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" +"checksum block-buffer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1339a1042f5d9f295737ad4d9a6ab6bf81c84a933dba110b9200cd6d1448b814" +"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" +"checksum coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c06169f5beb7e31c7c67ebf5540b8b472d23e3eade3b2ec7d1f5b504a85f91bd" +"checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299" +"checksum custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9" +"checksum digest 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e5b29bf156f3f4b3c4f610a25ff69370616ae6e0657d416de22645483e72af0a" +"checksum either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18785c1ba806c258137c937e44ada9ee7e69a37e3c72077542cd2f069d78562a" +"checksum error-chain 0.11.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)" = "38d3a55d9a7a456748f2a3912c0941a5d9a68006eb15b3c3c9836b8420dc102d" +"checksum futures 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4b63a4792d4f8f686defe3b39b92127fea6344de5d38202b2ee5a11bbbf29d6a" +"checksum gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)" = "e8310f7e9c890398b0e80e301c4f474e9918d2b27fca8f48486ca775fa9ffc5a" +"checksum generic-array 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6181b378c58e5aacf4d3e17836737465cb2857750b53f6b46672a3509f2a8d9d" +"checksum lamport_sigs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2169eee511fb4b2af1d9581f74d9503b5a86e4dbfa52ca1f5ee0d1193bf1d913" +"checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf" +"checksum libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)" = "8a014d9226c2cc402676fbe9ea2e15dd5222cd1dd57f576b5b283178c944a264" +"checksum libfuzzer-sys 0.1.0 (git+https://github.com/rust-fuzz/libfuzzer-sys.git)" = "" +"checksum magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf0336886480e671965f794bc9b6fce88503563013d1bfb7a502c81fe3ac527" +"checksum magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40d014c7011ac470ae28e2f76a02bfea4a8480f73e701353b49ad7a8d75f4699" +"checksum merkle 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "204bbb6953e7cc6c2cec3f63e108f0d61311a3dab33d33582b1f6f4d4ae6f992" +"checksum merkle_sigs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b446a57d9a060a9db764b6c6bd44bf79e46c512733ed9b6c23206e74394d3255" +"checksum nodrop 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "52cd74cd09beba596430cc6e3091b74007169a56246e1262f0ba451ea95117b2" +"checksum num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aec53c34f2d0247c5ca5d32cca1478762f301740468ee9ee6dcb7a0dd7a0c584" +"checksum odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "c3df9b730298cea3a1c3faa90b7e2f9df3a9c400d0936d6015e6165734eefcba" +"checksum protobuf 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "568a15e4d572d9a5e63ae3a55f84328c984842887db179b40b4cc6a608bac6a4" +"checksum rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "eb250fd207a4729c976794d03db689c9be1d634ab5a1c9da9492a13d8fecbcdf" +"checksum rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a77c51c07654ddd93f6cb543c7a849863b03abc7e82591afda6dc8ad4ac3ac4a" +"checksum rayon-core 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7febc28567082c345f10cddc3612c6ea020fc3297a1977d472cf9fdb73e6e493" +"checksum ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2a6dc7fc06a05e6de183c5b97058582e9da2de0c136eafe49609769c507724" +"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" +"checksum scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c79eb2c3ac4bc2507cda80e7f3ac5b88bd8eae4c0914d5663e6a8933994be918" +"checksum sha3 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "26405905b6a56a94c60109cfda62610507ac14a65be531f5767dec5c5a8dd6a0" +"checksum typenum 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "13a99dc6780ef33c78780b826cf9d2a78840b72cae9474de4bcaf9051e60ebbd" +"checksum untrusted 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6b65243989ef6aacd9c0d6bd2b822765c3361d8ed352185a6f3a41f3a718c673" diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml new file mode 100644 index 0000000..d84047f --- /dev/null +++ b/fuzz/Cargo.toml @@ -0,0 +1,37 @@ + +[package] +name = "rusty_secrets-fuzz" +version = "0.0.1" +authors = ["Automatically generated"] +publish = false + +[package.metadata] +cargo-fuzz = true + +[dependencies] +arbitrary = "0.1.0" + +[dependencies.rusty_secrets] +path = ".." +[dependencies.libfuzzer-sys] +git = "https://github.com/rust-fuzz/libfuzzer-sys.git" + +# Prevent this from interfering with workspaces +[workspace] +members = ["."] + +[[bin]] +name = "ss1_1" +path = "fuzz_targets/ss1_1.rs" + +[[bin]] +name = "thss_1" +path = "fuzz_targets/thss_1.rs" + +[[bin]] +name = "sss_1" +path = "fuzz_targets/sss_1.rs" + +[[bin]] +name = "wrapped_secrets_1" +path = "fuzz_targets/wrapped_secrets_1.rs" diff --git a/fuzz/fuzz_targets/ss1_1.rs b/fuzz/fuzz_targets/ss1_1.rs new file mode 100644 index 0000000..339553f --- /dev/null +++ b/fuzz/fuzz_targets/ss1_1.rs @@ -0,0 +1,24 @@ +#![no_main] +#[macro_use] +extern crate libfuzzer_sys; +extern crate rusty_secrets; +extern crate arbitrary; + +use rusty_secrets::dss::ss1::*; +use arbitrary::{RingBuffer, Unstructured}; + +fuzz_target!(|data: &[u8]| { + // --- + if let Ok(mut buffer) = RingBuffer::new(data, data.len()) { + let mut kn = vec![0; 2]; + buffer.fill_buffer(&mut kn).unwrap(); + + let k = kn[0]; + let n = kn[1]; + + split_secret(k, n, &data, Reproducibility::reproducible(), &None) + .and_then(|ss| recover_secret(&ss)) + .map(|_| ()) + .unwrap_or(()) + } +}); diff --git a/fuzz/fuzz_targets/sss_1.rs b/fuzz/fuzz_targets/sss_1.rs new file mode 100644 index 0000000..ef2a65e --- /dev/null +++ b/fuzz/fuzz_targets/sss_1.rs @@ -0,0 +1,25 @@ +#![no_main] +extern crate arbitrary; +#[macro_use] +extern crate libfuzzer_sys; +extern crate rusty_secrets; + +use rusty_secrets::sss; +use arbitrary::{RingBuffer, Unstructured}; + +fuzz_target!(|data: &[u8]| { + // --- + if let Ok(mut buffer) = RingBuffer::new(data, data.len()) { + let mut kn = vec![0; 2]; + buffer.fill_buffer(&mut kn).unwrap(); + + let k = kn[0]; + let n = kn[1]; + + sss::split_secret(k, n, &data, false) + .map_err(|err| err.into()) + .and_then(|ss| sss::recover_secret(&ss, false)) + .map(|_| ()) + .unwrap_or(()) + } +}); diff --git a/fuzz/fuzz_targets/thss_1.rs b/fuzz/fuzz_targets/thss_1.rs new file mode 100644 index 0000000..e3c0588 --- /dev/null +++ b/fuzz/fuzz_targets/thss_1.rs @@ -0,0 +1,24 @@ +#![no_main] +#[macro_use] +extern crate libfuzzer_sys; +extern crate rusty_secrets; +extern crate arbitrary; + +use rusty_secrets::dss::thss::*; +use arbitrary::{RingBuffer, Unstructured}; + +fuzz_target!(|data: &[u8]| { + // --- + if let Ok(mut buffer) = RingBuffer::new(data, data.len()) { + let mut kn = vec![0; 2]; + buffer.fill_buffer(&mut kn).unwrap(); + + let k = kn[0]; + let n = kn[1]; + + split_secret(k, n, &data, &None) + .and_then(|ss| recover_secret(&ss)) + .map(|_| ()) + .unwrap_or(()) + } +}); diff --git a/fuzz/fuzz_targets/wrapped_secrets_1.rs b/fuzz/fuzz_targets/wrapped_secrets_1.rs new file mode 100644 index 0000000..c454cd5 --- /dev/null +++ b/fuzz/fuzz_targets/wrapped_secrets_1.rs @@ -0,0 +1,25 @@ +#![no_main] +extern crate arbitrary; +#[macro_use] +extern crate libfuzzer_sys; +extern crate rusty_secrets; + +use rusty_secrets::wrapped_secrets; +use arbitrary::{RingBuffer, Unstructured}; + +fuzz_target!(|data: &[u8]| { + // --- + if let Ok(mut buffer) = RingBuffer::new(data, data.len()) { + let mut kn = vec![0; 2]; + buffer.fill_buffer(&mut kn).unwrap(); + + let k = kn[0]; + let n = kn[1]; + + wrapped_secrets::split_secret(k, n, &data, false) + .map_err(|err| err.into()) + .and_then(|ss| wrapped_secrets::recover_secret(&ss, false)) + .map(|_| ()) + .unwrap_or(()) + } +}); diff --git a/protobuf/.gitignore b/protobuf/.gitignore new file mode 100644 index 0000000..c4fff02 --- /dev/null +++ b/protobuf/.gitignore @@ -0,0 +1 @@ +_out/ diff --git a/protobuf/Makefile b/protobuf/Makefile new file mode 100644 index 0000000..7ecfba2 --- /dev/null +++ b/protobuf/Makefile @@ -0,0 +1,42 @@ +SHELL = bash + +PROTOC := protoc + +DEST_DIR := ../src/proto + +BASE_PROTOS := $(wildcard *.proto) +BASE_RUSTS := $(addprefix $(DEST_DIR)/, $(BASE_PROTOS:.proto=.rs)) + +DSS_PROTOS := $(wildcard dss/*.proto) +DSS_RUSTS := $(addprefix $(DEST_DIR)/, $(DSS_PROTOS:.proto=.rs)) + +WRAPPED_PROTOS := $(wildcard wrapped/*.proto) +WRAPPED_RUSTS := $(addprefix $(DEST_DIR)/, $(WRAPPED_PROTOS:.proto=.rs)) + +OUT_DIR := _out + +.PHONY: all base wrapped dss clean + +all: base wrapped dss + +base: $(BASE_RUSTS) + +wrapped: $(WRAPPED_RUSTS) + +dss: $(DSS_RUSTS) + +$(DEST_DIR)/%.rs: %.proto + @echo -n "Processing '$<'..." + @$(RM) -r $(OUT_DIR) + @mkdir -p $(OUT_DIR) + @$(PROTOC) --rust_out $(OUT_DIR) $< + @echo " Done." + @echo -n "Moving generated file to '$(dir $@)'..." + @mkdir -p $(dir $@) + @mv $(OUT_DIR)/*.rs $(dir $@) + @echo " Done." + +clean: + $(RM) $(BASE_RUSTS) + $(RM) $(WRAPPED_RUSTS) + $(RM) $(DSS_RUSTS) diff --git a/protobuf/Secret.proto b/protobuf/Secret.proto deleted file mode 100644 index 935dca5..0000000 --- a/protobuf/Secret.proto +++ /dev/null @@ -1,11 +0,0 @@ -syntax = "proto3"; - -enum RustySecretsVersions { - INITIAL_RELEASE = 0; -} - -message RustySecret { - RustySecretsVersions version = 1; - bytes secret = 2; - string mime_type = 3; -} diff --git a/protobuf/dss/metadata.proto b/protobuf/dss/metadata.proto new file mode 100644 index 0000000..991cc9d --- /dev/null +++ b/protobuf/dss/metadata.proto @@ -0,0 +1,7 @@ +syntax = "proto3"; + +package dss; + +message MetaDataProto { + map tags = 1; +} diff --git a/protobuf/dss/secret.proto b/protobuf/dss/secret.proto new file mode 100644 index 0000000..872ea1e --- /dev/null +++ b/protobuf/dss/secret.proto @@ -0,0 +1,10 @@ +syntax = "proto3"; + +import "version.proto"; +import "dss/metadata.proto"; + +message SecretProto { + VersionProto version = 1; + bytes secret = 2; + dss.MetaDataProto meta_data = 3; +} diff --git a/protobuf/dss/share.proto b/protobuf/dss/share.proto new file mode 100644 index 0000000..c088010 --- /dev/null +++ b/protobuf/dss/share.proto @@ -0,0 +1,14 @@ +syntax = "proto3"; + +package dss; + +import "dss/metadata.proto"; + +message ShareProto { + uint32 id = 1; + uint32 threshold = 2; + uint32 shares_count = 3; + bytes data = 4; + bytes hash = 5; + dss.MetaDataProto meta_data = 6; +} diff --git a/protobuf/version.proto b/protobuf/version.proto new file mode 100644 index 0000000..5104f51 --- /dev/null +++ b/protobuf/version.proto @@ -0,0 +1,6 @@ + +syntax = "proto3"; + +enum VersionProto { + INITIAL_RELEASE = 0; +} diff --git a/protobuf/wrapped/secret.proto b/protobuf/wrapped/secret.proto new file mode 100644 index 0000000..b30e0c1 --- /dev/null +++ b/protobuf/wrapped/secret.proto @@ -0,0 +1,11 @@ +syntax = "proto3"; + +package wrapped; + +import "version.proto"; + +message SecretProto { + VersionProto version = 1; + bytes secret = 2; + string mime_type = 3; +} diff --git a/protobuf/ShareData.proto b/protobuf/wrapped/share.proto similarity index 70% rename from protobuf/ShareData.proto rename to protobuf/wrapped/share.proto index ec6a99d..3e29c52 100644 --- a/protobuf/ShareData.proto +++ b/protobuf/wrapped/share.proto @@ -1,6 +1,8 @@ syntax = "proto3"; -message ShareData { +package wrapped; + +message ShareProto { bytes shamir_data = 1; repeated bytes signature = 2; bytes proof = 3; diff --git a/src/custom_error.rs b/src/custom_error.rs deleted file mode 100644 index d108271..0000000 --- a/src/custom_error.rs +++ /dev/null @@ -1,183 +0,0 @@ -use std::convert; -use std::error::Error; -use std::fmt; -use std::io; -use std::num; - -/// Error struct used for generating an `io::Error` from a generic description. -#[derive(Debug)] -pub struct RustyError { - descr: &'static str, - detail: Option, - share_index: Option, - share_groups: Option>> -} - -#[derive(Debug)] -pub enum RustyErrorTypes { - DuplicateShareNum(u8), - DuplicateShareData(u8), - EmptyShares, - IncompatibleSets(Vec>), - InvalidSignature(u8, String), - MissingShares(u8, usize), - MissingSignature(u8), - SecretDeserializationIssue, - ShareParsingError(u8, String) -} - -impl RustyError { - /// Initializes a new error with a description and optional detail string. - fn new(descr: &'static str, detail: Option, share_index: Option, share_groups: Option>>) -> RustyError { - RustyError { - descr: descr, - detail: detail, - share_index: share_index, - share_groups: share_groups - } - } - - /// Returns a `RustyError` with a given `RustyErrorType`. - pub fn with_type(error_type: RustyErrorTypes) -> RustyError { - RustyError { - descr: RustyError::descr_for_type(&error_type), - detail: RustyError::detail_for_type(&error_type), - share_index: RustyError::share_num_for_type(&error_type), - share_groups: RustyError::share_groups_for_type(error_type), - } - } - - /// Returns the index of the share that raised the error, if any. - pub fn share_index(&self) -> Option { - self.share_index - } - - /// Returns the group of shares that were generated during the same secret share. - /// It can be used to provide a debug message to the user telling him what shares are incompatible. - pub fn share_groups(&self) -> Option>> { - self.share_groups.clone() - } - - fn descr_for_type(error_type: &RustyErrorTypes) -> &'static str { - match *error_type { - RustyErrorTypes::EmptyShares => "No shares were provided.", - RustyErrorTypes::IncompatibleSets(_) => "The shares are incompatible with each other.", - RustyErrorTypes::InvalidSignature(_, _) => "The signature of this share is not valid.", - RustyErrorTypes::MissingShares(_, _) => "The number of shares provided is insufficient to recover the secret.", - RustyErrorTypes::MissingSignature(_) => "Signature is missing while shares are required to be signed.", - RustyErrorTypes::SecretDeserializationIssue => "An issue was encountered deserializing the secret. - Updating to the latest version of RustySecrets might help fix this.", - RustyErrorTypes::ShareParsingError(_, _) => "This share is incorrectly formatted.", - RustyErrorTypes::DuplicateShareNum(_) => "This share number has already been used by a previous share.", - RustyErrorTypes::DuplicateShareData(_) => "The data encoded in this share is the same as the one found in a previous share." - } - } - - fn detail_for_type(error_type: &RustyErrorTypes) -> Option { - match *error_type { - RustyErrorTypes::MissingShares(required, found) => Some(format!("{} shares are required to recover the secret, - found only {}.", required, found)), - RustyErrorTypes::ShareParsingError(_, ref description) => Some(description.clone()), - _ => None - } - } - - fn share_groups_for_type(error_type: RustyErrorTypes) -> Option>>{ - match error_type { - RustyErrorTypes::IncompatibleSets(groups) => Some(groups), - _ => None - } - } - - fn share_num_for_type(error_type: &RustyErrorTypes) -> Option { - match *error_type { - RustyErrorTypes::InvalidSignature(share_num, _) - | RustyErrorTypes::MissingSignature(share_num) - | RustyErrorTypes::ShareParsingError(share_num, _) - | RustyErrorTypes::DuplicateShareNum(share_num) - | RustyErrorTypes::DuplicateShareData(share_num) => Some(share_num), - _ => None - } - } -} - -impl fmt::Display for RustyError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self.detail { - None => write!(f, "{}", self.descr), - Some(ref detail) => write!(f, "{} ({})", self.descr, detail), - } - } -} - -impl Error for RustyError { - fn description(&self) -> &str { - self.descr - } - fn cause(&self) -> Option<&Error> { - None - } -} - -impl From for RustyError { - fn from(err: io::Error) -> RustyError { - let descr = err.description().to_owned(); - - RustyError::new("from io:Error", Some(descr), None, None) - } -} - -impl From for io::Error { - fn from(me: RustyError) -> io::Error { - io::Error::new(io::ErrorKind::Other, me) - } -} - -/// Returns an `io::Error` from description string and optional detail string. -/// Particularly useful in `Result` expressions. -pub fn other_io_err(descr: &'static str, detail: Option, - share_num: Option, share_groups: Option>>) -> io::Error { - convert::From::from(RustyError::new(descr, detail, share_num, share_groups)) -} - -/// maps a `ParseIntError` to an `Error` -pub fn pie2error(p: num::ParseIntError) -> RustyError { - RustyError::new("Integer parsing error", Some(p.to_string()), None, None) -} - -#[cfg(test)] -mod tests_custom_err { - use std::error; - use custom_error::RustyError; - - #[test] - fn test_custom_error() { - let desc = "Boring error description"; - let detail = "More of it"; - let ewd = RustyError::new(desc, Some(detail.to_string()), None, None); - - assert_eq!(error::Error::description(&ewd), desc); - match error::Error::cause(&ewd) { - Some(_) => assert!(false), - None => assert!(true), - } - let _formated_err = format!("{}", ewd); - let ewod = RustyError::new(desc, None, None, None); - let _formated_err = format!("{}", ewod); - } -} - -#[cfg(test)] -mod tests_std_err { - use std::error::Error; - use custom_error::pie2error; - - #[test] - fn test_parse_errors() { - let nan = "2a".to_string(); - match nan.parse::().map_err(pie2error) { - Ok(_) => assert!(false), - Err(x) => assert_eq!("Integer parsing error", x.description()), - } - } -} diff --git a/src/dss/format.rs b/src/dss/format.rs new file mode 100644 index 0000000..70669b5 --- /dev/null +++ b/src/dss/format.rs @@ -0,0 +1,73 @@ +use std::error::Error; + +use protobuf::{self, Message}; +use base64; + +use errors::*; +use proto::dss::ShareProto; + +const BASE64_CONFIG: base64::Config = base64::STANDARD_NO_PAD; + +pub(crate) fn format_share_protobuf(share: &ShareProto) -> String { + let bytes = share.write_to_bytes().unwrap(); + let base64_data = base64::encode_config(&bytes, BASE64_CONFIG); + format!("{}-{}-{}", share.threshold, share.id, base64_data) +} + +pub(crate) fn parse_share_protobuf(raw: &str) -> Result { + let (threshold, id, base64_data) = parse_raw_share(raw)?; + + let data = base64::decode_config(&base64_data, BASE64_CONFIG).chain_err(|| { + ErrorKind::ShareParsingError("Base64 decoding of data block failed".to_string()) + })?; + + let share_proto = protobuf::parse_from_bytes::(data.as_slice()).map_err(|e| { + ErrorKind::ShareParsingError(format!( + "Protobuf decoding of data block failed with error: {} .", + e.description() + )) + })?; + + if threshold != share_proto.threshold { + bail! { + ErrorKind::ShareParsingError( + format!( + "Incompatible thresholds between decoded Protobuf provided \ + (k={}) and raw share (k={})", share_proto.threshold, threshold + ) + )} + } + + if id != share_proto.id { + bail! { + ErrorKind::ShareParsingError( + format!( + "Incompatible ids between decoded Protobuf provided \ + (i={}) and raw share (i={})", share_proto.id, id + ) + )} + } + + Ok(share_proto) +} + +fn parse_raw_share(raw: &str) -> Result<(u32, u32, String)> { + let parts: Vec<_> = raw.trim().split('-').collect(); + + if parts.len() != 3 { + bail! { + ErrorKind::ShareParsingError( + format!( + "Expected 3 parts separated by a minus sign. Found {}.", + raw + ), + ) + }; + } + + let mut iter = parts.into_iter(); + let k = iter.next().unwrap().parse::()?; + let i = iter.next().unwrap().parse::()?; + let data = iter.next().unwrap(); + Ok((k, i, data.to_string())) +} diff --git a/src/dss/metadata.rs b/src/dss/metadata.rs new file mode 100644 index 0000000..86c3f92 --- /dev/null +++ b/src/dss/metadata.rs @@ -0,0 +1,31 @@ +use std::collections::BTreeMap; +use ring::digest; + +/// A share's public metadata. +#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Default)] +pub struct MetaData { + /// The tags associated with the share + pub tags: BTreeMap, +} + +impl MetaData { + /// Construct a new MetaData struct. + pub fn new() -> Self { + MetaData { + tags: BTreeMap::new(), + } + } + + /// Construct a new MetaData struct, holding the given tags + pub fn with_tags(tags: BTreeMap) -> Self { + Self { tags } + } + + pub(crate) fn hash_into(&self, ctx: &mut digest::Context) { + for (tag, value) in &self.tags { + ctx.update(tag.as_bytes()); + ctx.update(b":"); + ctx.update(value.as_bytes()); + } + } +} diff --git a/src/dss/mod.rs b/src/dss/mod.rs new file mode 100644 index 0000000..ab45caa --- /dev/null +++ b/src/dss/mod.rs @@ -0,0 +1,59 @@ +//! Defines two different deterministic sharing schemes, ThSS and SS1. +//! +//! # Deterministic secret sharing +//! +//! TODO: Doc +//! +//! # Schemes +//! +//! The two schemes differ by the security properties that they satisfy. +//! The following table summarizes which properties are satisfied by each scheme. +//! The definitions of the properties can be found under the 'Security properties' section. +//! +//! **Scheme / Property** | **Basic** | **Priv1** | **Priv2** | **Auth1** | **Auth2** | **ErrDet** | **Repro** | +//! :--------------------:|:---------:|:---------:|:---------:|:---------:|:---------:|:----------:|:---------:| +//! **ThSS** | Yes | Yes | No | No | No | Yes | No | +//! **SS1** | Yes | Yes | Yes | Yes | Yes | Yes | Yes | +//! +//! # Security properties +//! +//! **Property** | **Description** +//! :-----------:|----------------|---------------- +//! **Basic** | Basic correctness: If you attempt to recover a secret from an authorized set of shares that were obtained by sharing out a secret **M** using an access structure **A**, you're sure to get back **A** and **M**.
Note: in this implementation **A** is not actually returned, but definitely could. +//! **Priv1** | Standard privacy notation: When the coins are used by the dealer are uniformly random, unauthorized sets of shares have no computationally extractable information about the underlying secret. +//! **Priv2** | Privacy for deterministic or hedged schemes: extract whatever entropy one can from the underlying secret. If it’s adequate, no additional randomness is needed in order to achieve a meaningful notion of privacy. +//! **Auth1** | A share obtained from an honest dealer commits it to a single underlying secret: that and only that value can be recovered. +//! **Auth2** | A share obtained even from a dishonest dealer commits it to a single underlying secret: that and only that value might be recovered. Implies Auth1. +//! **ErrDet** | An inauthentic set of shares produced by an adversary will be flagged as such when fed to the recovery algorithm. +//! **Repro** | Share reproducible: The scheme can produce shares in a deterministic way. + +pub mod thss; +pub mod ss1; + +mod metadata; + +mod format; +mod random; +mod utils; + +/// Define the access structure used to deal and recover the shares. +/// +/// For example, if one wants to deal 10 shares, and require 7 of them to +/// recover the secret, one would express it as: +/// +/// ```rust +/// # use rusty_secrets::dss::AccessStructure; +/// AccessStructure { +/// threshold: 7, +/// shares_count: 10, +/// }; +/// ``` +#[derive(Copy, Clone, Debug)] +pub struct AccessStructure { + /// The minimum amount of shares required to recover the secret. + pub threshold: u8, + + /// The total number of shares generated when splitting up the secret. + /// Always greater than or equal to `threshold`. + pub shares_count: u8, +} diff --git a/src/dss/random.rs b/src/dss/random.rs new file mode 100644 index 0000000..a09a0ec --- /dev/null +++ b/src/dss/random.rs @@ -0,0 +1,66 @@ +use std; + +use errors::*; + +use ring::error::Unspecified; +use ring::rand::SecureRandom; + +/// We bound the message size at about 16MB to avoid overflow in `random_bytes_count`. +/// Moreover, given the current performances, it is almost unpractical to run +/// the sharing scheme on message larger than that. +pub(crate) const MAX_MESSAGE_SIZE: usize = std::usize::MAX / (std::u8::MAX - 1) as usize; +/// Minimum allowed message size in bytes +pub(crate) static MIN_MESSAGE_SIZE: usize = 1; + +/// Returns the number of random bytes to read from the secure random number generator. +/// As defined in section 3.1 of the 'New Directions in Secret Sharing' paper. +pub(crate) fn random_bytes_count(threshold: u8, message_size: usize) -> usize { + assert!(threshold >= MIN_THRESHOLD); + assert!(message_size >= MIN_MESSAGE_SIZE); + assert!(message_size <= MAX_MESSAGE_SIZE); + + (threshold as usize - 1) * message_size +} + +/// Attempts to read `count` random bytes from the given secure random generator. +pub(crate) fn random_bytes(random: &SecureRandom, count: usize) -> Result> { + if count == 0 { + return Ok(Vec::new()); + } + + let mut rl = vec![0; count]; + random + .fill(&mut rl) + .chain_err(|| ErrorKind::CannotGenerateRandomNumbers)?; + + Ok(rl) +} + +/// An implementation of SecureRandom that fills the output slice with the slice in `src`. +/// The length of `src` must be larger than any slice that we attempt to fill. +pub(crate) struct FixedRandom { + src: Vec, +} + +impl FixedRandom { + /// Create a new fixed random generator. + /// The length of `src` must be larger than any slice that we attempt to fill. + pub(crate) fn new(src: Vec) -> Self { + if src.is_empty() { + panic!("The source slice of FixedRandom cannot be empty!"); + } + FixedRandom { src } + } +} + +impl SecureRandom for FixedRandom { + fn fill(&self, dst: &mut [u8]) -> std::result::Result<(), Unspecified> { + if dst.len() > self.src.len() { + return Err(Unspecified); + } + + let len = dst.len(); + dst.copy_from_slice(&self.src[0..len]); + Ok(()) + } +} diff --git a/src/dss/ss1/mod.rs b/src/dss/ss1/mod.rs new file mode 100644 index 0000000..78335d2 --- /dev/null +++ b/src/dss/ss1/mod.rs @@ -0,0 +1,194 @@ +//! Implements the `SS1` deterministic threshold secret sharing scheme. +//! +//! This scheme is implemented as the *T2 transform* over the ThSS threshold sharing scheme. +//! found in the `rusty_secrets::dss::thss` module. +//! +//! # Security properties +//! +//! This scheme satisfies the following security properties: +//! +//! **Property** | **Satisifed?** | **Description** +//! -------------|----------------|---------------- +//! **Basic** | Yes | Basic correctness: If you attempt to recover a secret from an authorized set of shares that were obtained by sharing out a secret **M** using an access structure **A**, you're sure to get back **A** and **M**.
Note: in this implementation **A** is not actually returned, but definitely could. +//! **Priv1** | Yes | Standard privacy notation: When the coins are used by the dealer are uniformly random, unauthorized sets of shares have no computationally extractable information about the underlying secret. +//! **Priv2** | Yes | Privacy for deterministic or hedged schemes: extract whatever entropy one can from the underlying secret. If it’s adequate, no additional randomness is needed in order to achieve a meaningful notion of privacy. +//! **Auth1** | Yes | A share obtained from an honest dealer commits it to a single underlying secret: that and only that value can be recovered. +//! **Auth2** | Yes | A share obtained even from a dishonest dealer commits it to a single underlying secret: that and only that value might be recovered. Implies Auth1. +//! **ErrDet** | Yes | An inauthentic set of shares produced by an adversary will be flagged as such when fed to the recovery algorithm. +//! **Repro** | Yes | Share reproducible: The scheme can produce shares in a deterministic way. +//! +//! # References +//! +//! - *New Directions in Secret Sharing* (TODO: Full reference) + +use errors::*; + +mod serialize; + +mod share; +pub use self::share::*; + +mod scheme; +use self::scheme::SS1; +pub use self::scheme::Reproducibility; + +use dss::AccessStructure; + +/// Performs threshold k-out-of-n deterministic secret sharing. +/// +/// # Examples +/// +/// ``` +/// use rusty_secrets::dss::ss1::{self, Reproducibility, MetaData}; +/// +/// let secret = "These programs were never about terrorism: they’re about economic spying, \ +/// social control, and diplomatic manipulation. They’re about power."; +/// +/// let mut metadata = MetaData::new(); +/// metadata.tags.insert("mime_type".to_string(), "text/plain".to_string()); +/// +/// match ss1::split_secret(7, 10, &secret.as_bytes(), Reproducibility::reproducible(), &Some(metadata)) { +/// Ok(shares) => { +/// // Do something with the shares +/// }, +/// Err(_) => { +/// // Deal with error +/// } +/// } +/// ``` +pub fn split_secret( + k: u8, + n: u8, + secret: &[u8], + reproducibility: Reproducibility, + metadata: &Option, +) -> Result> { + SS1::default().split_secret(k, n, secret, reproducibility, metadata) +} + +/// Recovers the secret from a k-out-of-n deterministic secret sharing scheme (`SS1`). +/// +/// At least `k` distinct shares need to be provided to recover the secret. +/// +/// # Examples +/// +/// ```rust +/// use rusty_secrets::dss::ss1::{self, Reproducibility, MetaData}; +/// +/// let secret = "These programs were never about terrorism: they’re about economic spying, \ +/// social control, and diplomatic manipulation. They’re about power."; +/// +/// let mut metadata = MetaData::new(); +/// metadata.tags.insert("mime_type".to_string(), "text/plain".to_string()); +/// +/// let shares = ss1::split_secret( +/// 7, +/// 10, +/// &secret.as_bytes(), +/// Reproducibility::reproducible(), +/// &Some(metadata) +/// ).unwrap(); +/// +/// match ss1::recover_secret(&shares) { +/// Ok((secret, access_structure, metadata)) => { +/// // Do something with the secret and the metadata +/// }, +/// Err(e) => { +/// // Deal with the error +/// } +/// } +/// ``` +pub fn recover_secret(shares: &[Share]) -> Result<(Vec, AccessStructure, Option)> { + SS1::default().recover_secret(shares) +} + +#[cfg(test)] +mod tests { + + use super::*; + + #[test] + fn nonreproducible_split_then_recover_yields_original_secret() { + let secret = "Hello, World!".to_string().into_bytes(); + + let shares = split_secret(7, 10, &secret, Reproducibility::none(), &None).unwrap(); + + assert_eq!(shares.len(), 10); + + let (recovered, access_structure, metadata) = recover_secret(&shares[2..9]).unwrap(); + + assert_eq!(secret, recovered); + assert_eq!(access_structure.threshold, 7); + assert_eq!(access_structure.shares_count, 10); + assert_eq!(None, metadata); + } + + #[test] + fn reproducible_split_then_recover_yields_original_secret() { + let secret = "Hello, World!".to_string().into_bytes(); + + let shares = split_secret(7, 10, &secret, Reproducibility::reproducible(), &None).unwrap(); + + assert_eq!(shares.len(), 10); + + let (recovered, access_structure, metadata) = recover_secret(&shares[2..9]).unwrap(); + + assert_eq!(secret, recovered); + assert_eq!(access_structure.threshold, 7); + assert_eq!(access_structure.shares_count, 10); + assert_eq!(None, metadata); + } + + #[test] + fn seeded_reproducible_split_then_recover_yields_original_secret() { + let secret = "Hello, World!".to_string().into_bytes(); + + let seed = vec![1, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16u8]; + let shares = split_secret(7, 10, &secret, Reproducibility::seeded(seed), &None).unwrap(); + + assert_eq!(shares.len(), 10); + + let (recovered, access_structure, metadata) = recover_secret(&shares[2..9]).unwrap(); + + assert_eq!(secret, recovered); + assert_eq!(access_structure.threshold, 7); + assert_eq!(access_structure.shares_count, 10); + assert_eq!(None, metadata); + } + + #[test] + fn reproducible_split() { + let secret = "Hello, World!".to_string().into_bytes(); + + let shares_1 = + split_secret(7, 10, &secret, Reproducibility::reproducible(), &None).unwrap(); + let shares_2 = + split_secret(7, 10, &secret, Reproducibility::reproducible(), &None).unwrap(); + + assert_eq!(shares_1, shares_2); + } + + #[test] + fn nonreproducible_split() { + let secret = "Hello, World!".to_string().into_bytes(); + + let shares_1 = split_secret(7, 10, &secret, Reproducibility::none(), &None).unwrap(); + let shares_2 = split_secret(7, 10, &secret, Reproducibility::none(), &None).unwrap(); + + assert!(shares_1 != shares_2); + } + + #[test] + fn seeded_split() { + let secret = "Hello, World!".to_string().into_bytes(); + + let seed = vec![1, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16u8]; + let shares_1 = + split_secret(7, 10, &secret, Reproducibility::seeded(seed.clone()), &None).unwrap(); + let shares_2 = + split_secret(7, 10, &secret, Reproducibility::seeded(seed.clone()), &None).unwrap(); + + assert_eq!(shares_1, shares_2); + } + +} diff --git a/src/dss/ss1/scheme.rs b/src/dss/ss1/scheme.rs new file mode 100644 index 0000000..0801a28 --- /dev/null +++ b/src/dss/ss1/scheme.rs @@ -0,0 +1,317 @@ +use std::collections::HashSet; + +use ring::{hkdf, hmac}; +use ring::rand::{SecureRandom, SystemRandom}; +use ring::digest::{Context, SHA256}; +use rand::{ChaChaRng, Rng, SeedableRng}; + +use errors::*; +use dss::{thss, AccessStructure}; +use dss::thss::{MetaData, ThSS}; +use dss::random::{random_bytes_count, FixedRandom, MAX_MESSAGE_SIZE}; +use share::validation::{validate_share_count, validate_shares}; +use super::share::*; +use dss::utils; +use vol_hash::VOLHash; + +/// We bound the message size at about 16MB to avoid overflow in `random_bytes_count`. +/// Moreover, given the current performances, it is almost unpractical to run +/// the sharing scheme on message larger than that. +const MAX_SECRET_SIZE: usize = MAX_MESSAGE_SIZE; + +const DEFAULT_PRESEED: &[u8] = b"rusty_secrets::dss::ss1"; + +/// There are situations where it's useful to generate shares in a reproducible manner. +/// In particular, this allows a secret that’s in someone’s head, a passphrase, +/// to be shared out in a manner in which different shares can be given to +/// different people at different points in time. +/// +/// On the other hand, there is some privacy cost. +/// For example, if you know the secret is one of two possibilities, +/// M0 or M1, in a share-reproducible scheme, acquiring a single share +/// will probably let you decide which of the two possibilities it was. +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum Reproducibility { + /// Shares will be produced in a deterministic way, using + /// a default, fixed seed for the internal random number generator + /// used to generate entropy. + Reproducible, + /// Shares will be produced in non-deterministic way, using + /// the system's random number generator to produce entropy. + None, + /// Shares will be produced in a deterministic way, using + /// the given seed for the internal random number generator used to + /// generate entropy. + Seeded(Vec), + /// Shares will be produced in a deterministic way, using + /// the given byte vector as the entropy source. + /// *Warning: Never use this variant unless you are sure of what you are doing* + WithEntropy(Vec), +} + +impl Reproducibility { + /// Shares will be produced in a deterministic way, using + /// a default, fixed seed for the internal random number generator + /// used to generate entropy. + pub fn reproducible() -> Self { + Reproducibility::Reproducible + } + + /// Shares will be produced in a deterministic way, using + /// the given seed for the internal random number generator used to + /// generate entropy. + pub fn seeded(seed: Vec) -> Self { + assert!(!seed.is_empty(), "Reproducibility: seed cannot be empty"); + Reproducibility::Seeded(seed) + } + + /// Shares will be produced in a deterministic way, using + /// the given byte vector as the entropy source. + /// *Warning: Never use this variant unless you are sure of what you are doing* + pub fn with_entropy(entropy: Vec) -> Self { + assert!( + !entropy.is_empty(), + "Reproducibility: entropy cannot be empty" + ); + Reproducibility::WithEntropy(entropy) + } + + /// Shares will be produced in non-deterministic way, using + /// the system's random number generator to produce entropy. + pub fn none() -> Self { + Reproducibility::None + } +} + +/// Defines a `SS1` deterministic threshold secret sharing scheme. +/// +/// This scheme is implemented as the *T2 transform* over the ThSS threshold sharing scheme. +/// found in the `rusty_secrets::dss::thss` module. +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub(crate) struct SS1 { + /// How many random bytes to read from `random` to use as + /// padding to the hash function (param `r` from the paper) + /// and to the message in the underlying ThSS scheme. + pub random_padding_len: usize, + /// The length of the hash used for all shares (param `s` from the paper) + pub hash_len: usize, +} + +// TODO: Are those good parameters? +// TODO: Add max length ? +static DEFAULT_RANDOM_PADDING_LEN: usize = 512; // r +static MIN_RANDOM_PADDING_LEN: usize = 128; // r min +static DEFAULT_HASH_LEN: usize = 256; // s +static MIN_HASH_LEN: usize = 128; // s min + +impl Default for SS1 { + fn default() -> Self { + Self::new(DEFAULT_RANDOM_PADDING_LEN, DEFAULT_HASH_LEN).unwrap() + } +} + +impl SS1 { + /// Constructs a new sharing scheme + pub fn new(random_padding_len: usize, hash_len: usize) -> Result { + if random_padding_len < MIN_RANDOM_PADDING_LEN || hash_len < MIN_HASH_LEN { + bail!(ErrorKind::InvalidSS1Parameters( + random_padding_len, + hash_len, + )); + } + + Ok(Self { + random_padding_len, + hash_len, + }) + } + + /// Split a secret following a given sharing `scheme`, + /// with `threshold` being the number of shares necessary to recover the secret, + /// and `shares_count` the total number of shares to be dealt. + pub fn split_secret( + &self, + threshold: u8, + shares_count: u8, + secret: &[u8], + reproducibility: Reproducibility, + metadata: &Option, + ) -> Result> { + let (threshold, shares_count) = validate_share_count(threshold, shares_count)?; + let secret_len = secret.len(); + + if secret_len == 0 { + bail!(ErrorKind::EmptySecret); + } + if secret_len > MAX_SECRET_SIZE { + bail!(ErrorKind::SecretTooBig(secret_len, MAX_SECRET_SIZE)); + } + + let random_padding = self.generate_random_padding(reproducibility, secret, metadata)?; + + let mut vol_hash = VOLHash::new(&SHA256); + vol_hash.process(&[0]); + vol_hash.process(&[threshold, shares_count]); + vol_hash.process(secret); + vol_hash.process(&random_padding); + + let randomness_len = random_bytes_count(threshold, secret.len() + self.random_padding_len); + let total_hash_len = self.hash_len + randomness_len; + let mut full_hash = vec![0; total_hash_len]; + + vol_hash.finish(&mut full_hash); + let (hash, randomness) = full_hash.split_at(self.hash_len); + + let underlying = ThSS::new(Box::new(FixedRandom::new(randomness.to_vec()))); + + let message = [secret, &random_padding].concat(); + let shares = underlying.split_secret(threshold, shares_count, &message, metadata)?; + + let res = shares + .into_iter() + .map(|share| Share { + id: share.id, + threshold: share.threshold, + shares_count: share.shares_count, + data: share.data, + hash: hash.to_vec(), + metadata: share.metadata.clone(), + }) + .collect(); + + Ok(res) + } + + fn generate_random_padding( + &self, + reproducibility: Reproducibility, + secret: &[u8], + metadata: &Option, + ) -> Result> { + match reproducibility { + Reproducibility::None => { + let rng = SystemRandom::new(); + let mut result = vec![0u8; self.random_padding_len]; + rng.fill(&mut result) + .chain_err(|| ErrorKind::CannotGenerateRandomNumbers)?; + Ok(result) + } + Reproducibility::Reproducible => { + let seed = self.generate_seed(DEFAULT_PRESEED, secret, metadata); + let mut rng = ChaChaRng::from_seed(&seed); + let mut result = vec![0u8; self.random_padding_len]; + rng.fill_bytes(result.as_mut_slice()); + Ok(result) + } + Reproducibility::Seeded(preseed) => { + let seed = self.generate_seed(&preseed, secret, metadata); + let mut rng = ChaChaRng::from_seed(&seed); + let mut result = vec![0u8; self.random_padding_len]; + rng.fill_bytes(result.as_mut_slice()); + Ok(result) + } + Reproducibility::WithEntropy(entropy) => Ok(entropy), + } + } + + /// Generate a seed of 8 32-bits word for the ChaCha20 PRNG by hashing + /// together the preseed, secret, and metadata, in order to obtain a salt + /// for performing HKDF over the preseed. + fn generate_seed( + &self, + preseed: &[u8], + secret: &[u8], + metadata: &Option, + ) -> Vec { + let mut ctx = Context::new(&SHA256); + ctx.update(preseed); + ctx.update(secret); + for md in metadata { + md.hash_into(&mut ctx); + } + let preseed_hash = ctx.finish(); + + let salt = hmac::SigningKey::new(&SHA256, &[]); + let mut seed_bytes = vec![0u8; 32]; + hkdf::extract_and_expand(&salt, preseed_hash.as_ref(), &[], &mut seed_bytes); + + // We can safely call `utils::slice_u8_to_slice_u32` because + // the `digest` produced with `SHA256` is 256 bits long, as is + // `seed_bytes`, and the latter can thus be represented both as a + // slice of 32 bytes or as a slice of 8 32-bit words. + utils::slice_u8_to_slice_u32(&seed_bytes).to_vec() + } + + /// Recover the secret from the given set of shares + pub fn recover_secret( + &self, + shares: &[Share], + ) -> Result<(Vec, AccessStructure, Option)> { + let (_, shares) = validate_shares(shares.to_vec())?; + + let underlying_shares = shares + .iter() + .map(|share| thss::Share { + id: share.id, + threshold: share.threshold, + shares_count: share.shares_count, + data: share.data.clone(), + metadata: share.metadata.clone(), + }) + .collect::>(); + + let underlying = ThSS::default(); + let (mut secret, _, metadata) = underlying.recover_secret(&underlying_shares)?; + let secret_len = secret.len() - self.random_padding_len; + let random_padding = secret.split_off(secret_len); + // `secret` nows holds the secret + + let sub_scheme = Self::new(self.random_padding_len, self.hash_len)?; + + let test_shares = sub_scheme.split_secret( + shares[0].threshold, + shares[0].shares_count, + &secret, + Reproducibility::WithEntropy(random_padding.to_vec()), + &metadata, + )?; + + let access_structure = { + let first_share = shares.first().unwrap(); + AccessStructure { + threshold: first_share.threshold, + shares_count: first_share.shares_count, + } + }; + + self.verify_test_shares(shares, test_shares)?; + + Ok((secret, access_structure, metadata)) + } + + fn verify_test_shares( + &self, + mut shares: Vec, + mut test_shares: Vec, + ) -> Result<()> { + shares.sort_by_key(|share| share.id); + test_shares.sort_by_key(|share| share.id); + + let relevant_ids = shares.iter().map(|share| share.id).collect::>(); + let relevant_test_shares = test_shares + .iter() + .filter(|share| relevant_ids.contains(&share.id)); + let matching_shares = shares.iter().zip(relevant_test_shares); + + for (share, test_share) in matching_shares { + if share != test_share { + bail!(ErrorKind::MismatchingShares( + share.clone(), + test_share.clone(), + )); + } + } + + Ok(()) + } +} diff --git a/src/dss/ss1/serialize.rs b/src/dss/ss1/serialize.rs new file mode 100644 index 0000000..ca040df --- /dev/null +++ b/src/dss/ss1/serialize.rs @@ -0,0 +1,80 @@ +use errors::*; +use super::{MetaData, Share}; +use dss::format::{format_share_protobuf, parse_share_protobuf}; +use proto::dss::{MetaDataProto, ShareProto}; +use dss::utils::{btreemap_to_hashmap, hashmap_to_btreemap}; + +pub(crate) fn share_to_string(share: Share) -> String { + let proto = share_to_protobuf(share); + format_share_protobuf(&proto) +} + +pub(crate) fn share_from_string(raw: &str) -> Result { + let mut proto = parse_share_protobuf(raw)?; + + let metadata_proto = if proto.has_meta_data() { + Some(metadata_from_proto(proto.take_meta_data())) + } else { + None + }; + + let i = proto.get_id() as u8; + let k = proto.get_threshold() as u8; + let n = proto.get_shares_count() as u8; + + if k < 1 || i < 1 { + bail! { + ErrorKind::ShareParsingError( + format!("Found illegal share info: threshold = {}, identifier = {}.", k, i), + ) + } + } + + if n < 1 || k > n || i > n { + bail! { + ErrorKind::ShareParsingError( + format!("Found illegal share info: shares_count = {}, threshold = {}, identifier = {}.", n, k, i), + ) + } + } + + let share = Share { + id: i, + threshold: k, + shares_count: n, + data: proto.take_data(), + hash: proto.take_hash(), + metadata: metadata_proto, + }; + + Ok(share) +} + +pub(crate) fn share_to_protobuf(share: Share) -> ShareProto { + let mut proto = ShareProto::new(); + + proto.set_id(share.id.into()); + proto.set_threshold(share.threshold.into()); + proto.set_shares_count(share.shares_count.into()); + proto.set_data(share.data); + proto.set_hash(share.hash); + + if let Some(meta_data) = share.metadata { + let metadata_proto = metadata_to_proto(meta_data); + proto.set_meta_data(metadata_proto); + } + + proto +} + +fn metadata_to_proto(meta_data: MetaData) -> MetaDataProto { + let mut proto = MetaDataProto::new(); + proto.set_tags(btreemap_to_hashmap(meta_data.tags)); + proto +} + +fn metadata_from_proto(mut proto: MetaDataProto) -> MetaData { + MetaData { + tags: hashmap_to_btreemap(proto.take_tags()), + } +} diff --git a/src/dss/ss1/share.rs b/src/dss/ss1/share.rs new file mode 100644 index 0000000..4ca4178 --- /dev/null +++ b/src/dss/ss1/share.rs @@ -0,0 +1,57 @@ +use errors::*; +use share::IsShare; +use super::serialize::{share_from_string, share_to_string}; + +pub use dss::metadata::MetaData; + +/// A share identified by an `id`, a threshold `k`, a number of total shares `n`, +/// the `data` held in the share, and the share's `metadata`. +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Share { + /// The identifier of the share (varies between 1 and n where n is the total number of generated shares) + pub id: u8, + /// The number of shares necessary to recover the secret, aka a threshold + pub threshold: u8, + /// The total number of shares that have been dealt + pub shares_count: u8, + /// The share data itself + pub data: Vec, + /// The hash value common to the whole deal + pub hash: Vec, + /// The metadata associated with this share + pub metadata: Option, +} + +impl Share { + /// Format this share a string suitable for sharing + /// over an ASCII-encoded channel, such as a text file, + /// or an e-mail. + pub fn into_string(self) -> String { + share_to_string(self) + } + + /// Parse the given string into a `Share`. + /// The `raw` string must have been generated by the + /// `Share::to_string` method for it to succeed. + pub fn from_string(raw: &str) -> Result { + share_from_string(raw) + } +} + +impl IsShare for Share { + fn get_id(&self) -> u8 { + self.id + } + + fn get_data(&self) -> &[u8] { + &self.data + } + + fn get_threshold(&self) -> u8 { + self.threshold + } + + fn get_shares_count(&self) -> Option { + Some(self.shares_count) + } +} diff --git a/src/dss/thss/encode.rs b/src/dss/thss/encode.rs new file mode 100644 index 0000000..2e11400 --- /dev/null +++ b/src/dss/thss/encode.rs @@ -0,0 +1,37 @@ +use gf256::Gf256; +use poly::Poly; + +/// Encode the given `secret` using the `ThSS[N].Share` algorithm described +/// in the *New directions in Secret Sharing* paper. +/// +/// Reference: Figure 7 from the *New Directions in Secret Sharing* paper. +pub(crate) fn encode_secret(secret: &[u8], k: u8, share_id: u8, rands: &[u8]) -> Vec { + secret + .into_iter() + .enumerate() + .map(|(i, m)| { + let k_pred = (k - 1) as usize; + let coeffs = (0..k_pred) + .map(|l| { + let n = rands[i * k_pred + l]; + Gf256::from_byte(n) + }) + .collect(); + let poly = Poly::new(coeffs); + encode_secret_byte(*m, share_id, &poly) + }) + .collect() +} + +/// Encode the given secret byte `m`, by evaluating the given +/// polynomial at x = `j`, and adding the result to `m`. +/// +/// Reference: Figure 7 from the *New Directions in Secret Sharing* paper. +pub(crate) fn encode_secret_byte(m: u8, j: u8, poly: &Poly) -> u8 { + let mut acc = Gf256::from_byte(m); + for (l, &r) in poly.coeffs.iter().enumerate() { + let s = Gf256::from_byte(j).pow(l as u8 + 1); + acc = acc + r * s; + } + acc.to_byte() +} diff --git a/src/dss/thss/mod.rs b/src/dss/thss/mod.rs new file mode 100644 index 0000000..4c3534b --- /dev/null +++ b/src/dss/thss/mod.rs @@ -0,0 +1,122 @@ +//! Implements the `ThSS` threshold secret sharing scheme. +//! +//! This scheme satisfies the following security properties: +//! +//! **Property** | **Satisifed?** | **Description** +//! -------------|----------------|---------------- +//! **Basic** | Yes | Basic correctness: If you attempt to recover a secret from an authorized set of shares that were obtained by sharing out a secret **M** using an access structure **A**, you're sure to get back **A** and **M**.
Note: in this implementation **A** is not actually returned, but definitely could. +//! **Priv1** | Yes | Standard privacy notation: When the coins are used by the dealer are uniformly random, unauthorized sets of shares have no computationally extractable information about the underlying secret. +//! **Priv2** | No | Privacy for deterministic or hedged schemes: extract whatever entropy one can from the underlying secret. If it’s adequate, no additional randomness is needed in order to achieve a meaningful notion of privacy. +//! **Auth1** | No | A share obtained from an honest dealer commits it to a single underlying secret: that and only that value can be recovered. +//! **Auth2** | No | A share obtained even from a dishonest dealer commits it to a single underlying secret: that and only that value might be recovered. Implies Auth1. +//! **ErrDet** | Yes | An inauthentic set of shares produced by an adversary will be flagged as such when fed to the recovery algorithm. +//! **Repro** | No | Share reproducible: The scheme can produce shares in a deterministic way. + +use errors::*; + +mod encode; +mod serialize; + +mod share; +pub use self::share::*; + +mod scheme; +pub(crate) use self::scheme::ThSS; + +use dss::AccessStructure; + +/// Performs threshold k-out-of-n secret sharing using the `ThSS` scheme. +/// +/// # Examples +/// +/// ```rust +/// use rusty_secrets::dss::thss; +/// +/// let secret = "These programs were never about terrorism: they’re about economic spying, \ +/// social control, and diplomatic manipulation. They’re about power."; +/// +/// let mut metadata = thss::MetaData::new(); +/// metadata.tags.insert("mime_type".to_string(), "text/plain".to_string()); +/// +/// let result = thss::split_secret( +/// 7, +/// 10, +/// &secret.as_bytes(), +/// &Some(metadata) +/// ); +/// +/// match result { +/// Ok(shares) => { +/// // Do something with the shares +/// }, +/// Err(e) => { +/// // Deal with error +/// } +/// } +/// +/// ``` +pub fn split_secret( + k: u8, + n: u8, + secret: &[u8], + metadata: &Option, +) -> Result> { + ThSS::default().split_secret(k, n, secret, metadata) +} + +/// Recovers the secret from a k-out-of-n secret sharing scheme (`ThSS`). +/// +/// At least `k` distinct shares need to be provided to recover the secret. +/// +/// # Examples +/// +/// ```rust +/// use rusty_secrets::dss::thss; +/// +/// let secret = "These programs were never about terrorism: they’re about economic spying, \ +/// social control, and diplomatic manipulation. They’re about power."; +/// +/// let mut metadata = thss::MetaData::new(); +/// metadata.tags.insert("mime_type".to_string(), "text/plain".to_string()); +/// +/// let shares = thss::split_secret( +/// 7, +/// 10, +/// &secret.as_bytes(), +/// &Some(metadata) +/// ).unwrap(); +/// +/// match thss::recover_secret(&shares) { +/// Ok((secret, access_structure, metadata)) => { +/// // Do something with the secret and the metadata +/// }, +/// Err(e) => { +/// // Deal with the error +/// } +/// } +/// ``` +pub fn recover_secret(shares: &[Share]) -> Result<(Vec, AccessStructure, Option)> { + ThSS::default().recover_secret(shares) +} + +#[cfg(test)] +mod tests { + + use super::*; + + #[test] + fn split_then_recover_yields_original_secret() { + let secret = "Hello, World!".to_string().into_bytes(); + + let shares = split_secret(7, 10, &secret, &None).unwrap(); + assert_eq!(shares.len(), 10); + + let (recovered, access, metadata) = recover_secret(&shares[2..9]).unwrap(); + + assert_eq!(secret, recovered); + assert_eq!(access.threshold, 7); + assert_eq!(access.shares_count, 10); + assert_eq!(None, metadata); + } + +} diff --git a/src/dss/thss/scheme.rs b/src/dss/thss/scheme.rs new file mode 100644 index 0000000..c11cfd7 --- /dev/null +++ b/src/dss/thss/scheme.rs @@ -0,0 +1,134 @@ +//! Simple threshold secret sharing scheme + +use std::fmt; + +use ring::rand::{SecureRandom, SystemRandom}; + +use errors::*; +use gf256::Gf256; +use dss::random::{random_bytes, random_bytes_count, MAX_MESSAGE_SIZE}; +use share::validation::{validate_share_count, validate_shares}; +use lagrange; + +use super::AccessStructure; +use super::share::*; +use super::encode::encode_secret; + +/// We bound the message size at about 16MB to avoid overflow in `random_bytes_count`. +/// Moreover, given the current performances, it is almost unpractical to run +/// the sharing scheme on message larger than that. +const MAX_SECRET_SIZE: usize = MAX_MESSAGE_SIZE; + +/// A simple threshold sharing scheme +#[allow(missing_debug_implementations)] +pub(crate) struct ThSS { + /// The randomness source + random: Box, +} + +impl fmt::Debug for ThSS { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "ThSS") + } +} + +impl Default for ThSS { + fn default() -> Self { + Self::new(Box::new(SystemRandom::new())) + } +} + +impl ThSS { + /// Constructs a new sharing scheme + pub fn new(random: Box) -> Self { + Self { random } + } + + /// Split a secret following a given sharing `scheme`, + /// with `threshold` being the number of shares necessary to recover the secret, + /// and `shares_count` the total number of shares to be dealt. + pub fn split_secret( + &self, + threshold: u8, + shares_count: u8, + secret: &[u8], + metadata: &Option, + ) -> Result> { + let (threshold, shares_count) = validate_share_count(threshold, shares_count)?; + let secret_len = secret.len(); + + if secret_len == 0 { + bail!(ErrorKind::EmptySecret); + } + if secret_len > MAX_SECRET_SIZE { + bail!(ErrorKind::SecretTooBig(secret_len, MAX_SECRET_SIZE)); + } + + let rands_len = random_bytes_count(threshold, secret_len); + let rands = random_bytes(self.random.as_ref(), rands_len)?; + + let shares = (1..shares_count + 1) + .map(|id| { + let data = encode_secret(secret, threshold, id, &rands); + + Share { + id, + threshold, + shares_count, + data, + metadata: metadata.clone(), + } + }) + .collect(); + + Ok(shares) + } + + /// Recover the secret from the given set of shares + pub fn recover_secret( + &self, + shares: &[Share], + ) -> Result<(Vec, AccessStructure, Option)> { + let (threshold, shares) = validate_shares(shares.to_vec())?; + + let cypher_len = shares[0].data.len(); + + let polys = (0..cypher_len) + .map(|i| { + let points = shares + .iter() + .take(threshold as usize) + .map(|share| (Gf256::from_byte(share.id), Gf256::from_byte(share.data[i]))) + .collect::>(); + + lagrange::interpolate(&points) + }) + .collect::>(); + + for (i, poly) in polys.iter().enumerate() { + // Check remaining shares for consistency. + // See Figure 7 of the paper + let remaining_shares = shares.iter().enumerate().skip(threshold as usize); + + for (u, share) in remaining_shares { + let value = poly.evaluate_at(Gf256::from_byte(u as u8 + 1)).to_byte(); + if value != share.data[i] { + bail!(ErrorKind::InconsistentShares); + } + } + } + + let metadata = shares[0].metadata.clone(); + let secret = polys + .iter() + .map(|p| p.evaluate_at_zero().to_byte()) + .collect(); + + let access_structure = AccessStructure { + threshold: threshold, + shares_count: shares.first().unwrap().shares_count, + }; + + Ok((secret, access_structure, metadata)) + } +} diff --git a/src/dss/thss/serialize.rs b/src/dss/thss/serialize.rs new file mode 100644 index 0000000..7190934 --- /dev/null +++ b/src/dss/thss/serialize.rs @@ -0,0 +1,78 @@ +use errors::*; +use super::{MetaData, Share}; +use dss::format::{format_share_protobuf, parse_share_protobuf}; +use proto::dss::{MetaDataProto, ShareProto}; +use dss::utils::{btreemap_to_hashmap, hashmap_to_btreemap}; + +pub(crate) fn share_to_string(share: Share) -> String { + let proto = share_to_protobuf(share); + format_share_protobuf(&proto) +} + +pub(crate) fn share_from_string(raw: &str) -> Result { + let mut proto = parse_share_protobuf(raw)?; + + let metadata_proto = if proto.has_meta_data() { + Some(metadata_from_proto(proto.take_meta_data())) + } else { + None + }; + + let i = proto.get_id() as u8; + let k = proto.get_threshold() as u8; + let n = proto.get_shares_count() as u8; + + if k < 1 || i < 1 { + bail! { + ErrorKind::ShareParsingError( + format!("Found illegal share info: threshold = {}, identifier = {}.", k, i), + ) + } + } + + if n < 1 || k > n || i > n { + bail! { + ErrorKind::ShareParsingError( + format!("Found illegal share info: shares_count = {}, threshold = {}, identifier = {}.", n, k, i), + ) + } + } + + let share = Share { + id: i, + threshold: k, + shares_count: n, + data: proto.take_data(), + metadata: metadata_proto, + }; + + Ok(share) +} + +pub(crate) fn share_to_protobuf(share: Share) -> ShareProto { + let mut proto = ShareProto::new(); + + proto.set_id(share.id.into()); + proto.set_threshold(share.threshold.into()); + proto.set_shares_count(share.shares_count.into()); + proto.set_data(share.data); + + if let Some(meta_data) = share.metadata { + let metadata_proto = metadata_to_proto(meta_data); + proto.set_meta_data(metadata_proto); + } + + proto +} + +fn metadata_to_proto(meta_data: MetaData) -> MetaDataProto { + let mut proto = MetaDataProto::new(); + proto.set_tags(btreemap_to_hashmap(meta_data.tags)); + proto +} + +fn metadata_from_proto(mut proto: MetaDataProto) -> MetaData { + MetaData { + tags: hashmap_to_btreemap(proto.take_tags()), + } +} diff --git a/src/dss/thss/share.rs b/src/dss/thss/share.rs new file mode 100644 index 0000000..15a942b --- /dev/null +++ b/src/dss/thss/share.rs @@ -0,0 +1,55 @@ +use errors::*; +use share::IsShare; +use super::serialize::{share_from_string, share_to_string}; + +pub use dss::metadata::MetaData; + +/// A share identified by an `id`, a threshold `k`, a number of total shares `n`, +/// the `data` held in the share, and the share's `metadata`. +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Share { + /// The identifier of the share (varies between 1 and n where n is the total number of generated shares) + pub id: u8, + /// The number of shares necessary to recover the secret, aka a threshold + pub threshold: u8, + /// The total number of shares that have been dealt + pub shares_count: u8, + /// The share data itself + pub data: Vec, + /// The metadata associated with this share + pub metadata: Option, +} + +impl Share { + /// Format this share a string suitable for sharing + /// over an ASCII-encoded channel, such as a text file, + /// or an e-mail. + pub fn into_string(self) -> String { + share_to_string(self) + } + + /// Parse the given string into a `Share`. + /// The `raw` string must have been generated by the + /// `Share::to_string` method for it to succeed. + pub fn from_string(raw: &str) -> Result { + share_from_string(raw) + } +} + +impl IsShare for Share { + fn get_id(&self) -> u8 { + self.id + } + + fn get_data(&self) -> &[u8] { + &self.data + } + + fn get_threshold(&self) -> u8 { + self.threshold + } + + fn get_shares_count(&self) -> Option { + Some(self.shares_count) + } +} diff --git a/src/dss/utils.rs b/src/dss/utils.rs new file mode 100644 index 0000000..59a2362 --- /dev/null +++ b/src/dss/utils.rs @@ -0,0 +1,28 @@ +use std; + +use std::hash::Hash; +use std::collections::{BTreeMap, HashMap}; + +/// Transmutes a `&[u8]` into a `&[u32]`. +/// Despite `std::mem::transmute` being very unsafe in +/// general, this should actually be safe as long as +/// `input` contains a multiple of 4 bytes. +#[allow(unsafe_code)] +pub(crate) fn slice_u8_to_slice_u32(input: &[u8]) -> &[u32] { + assert_eq!(input.len() % 4, 0); + unsafe { std::mem::transmute(input) } +} + +/// Creates a `HashMap` from a `BTreeMap` +pub(crate) fn btreemap_to_hashmap(btree: BTreeMap) -> HashMap { + let mut hash = HashMap::new(); + hash.extend(btree.into_iter()); + hash +} + +/// Creates a `BTreeMap` from a `HashMap` +pub(crate) fn hashmap_to_btreemap(hash: HashMap) -> BTreeMap { + let mut btree = BTreeMap::new(); + btree.extend(hash.into_iter()); + btree +} diff --git a/src/errors.rs b/src/errors.rs new file mode 100644 index 0000000..c2b7496 --- /dev/null +++ b/src/errors.rs @@ -0,0 +1,141 @@ +//! Define the various error kinds specific to deterministic secret sharing. + +#![allow(unknown_lints, missing_docs)] + +use std::collections::HashSet; + +#[cfg(feature = "dss")] +use dss::ss1; + +/// Minimum allowed number of shares (n) +pub(crate) static MIN_SHARES: u8 = 2; +/// Minimum allowed threshold (k) +pub(crate) static MIN_THRESHOLD: u8 = 2; +/// Maximum allowed number of shares (k,n) +pub(crate) static MAX_SHARES: u8 = 255; +/// SSS Shares should be structured as k-n-data hence 3 parts +pub(crate) static SSS_SHARE_PARTS_COUNT: usize = 3; + +/// Create the Error, ErrorKind, ResultExt, and Result types +error_chain! { + errors { + ThresholdTooBig(k: u8, n: u8) { + description("Threshold k must be smaller than or equal to n") + display("Threshold k must be smaller than or equal to n, got: k = {}, n = {}.", k, n) + } + + ThresholdTooSmall(k: u8) { + description("Threshold k must be bigger than or equal to 2") + display("Threshold k must be bigger than or equal to 2, got: k = {}", k) + } + + SecretTooBig(len: usize, max: usize) { + description("The secret is too long") + display("The secret is too long, maximum allowed size = {} bytes, got {} bytes", max, len) + } + + InvalidShareCountMax(nb_shares: u8, max: u8) { + description("Number of shares is too big") + display("Number of shares must be smaller than or equal {}, got: {} shares.", max, nb_shares) + } + + InvalidShareCountMin(nb_shares: u8, min: u8) { + description("Number of shares is too small") + display("Number of shares must be larger than or equal {}, got: {} shares.", min, nb_shares) + } + + EmptySecret { + description("The secret cannot be empty") + display("The secret cannot be empty") + } + + EmptyShares { + description("No shares provided") + display("No shares were provided.") + } + + IncompatibleSets(sets: Vec>) { + description("The shares are incompatible with each other.") + display("The shares are incompatible with each other.") + } + + ShareIdentifierTooBig(id: u8, n: u8) { + description("Share identifier too big") + display("Found share identifier ({}) bigger than the maximum number of shares ({}).", id, n) + } + + MissingShares(provided: usize, required: usize) { + description("The number of shares provided is insufficient to recover the secret.") + display("{} shares are required to recover the secret, found only {}.", required, provided) + } + + InvalidSignature(share_id: u8, signature: String) { + description("The signature of this share is not valid.") + } + + MissingSignature(share_id: u8) { + description("Signature is missing while shares are required to be signed.") + } + + SecretDeserializationError { + description("An issue was encountered deserializing the secret. \ + Updating to the latest version of RustySecrets might help fix this.") + } + + ShareParsingError(reason: String) { + description("This share is incorrectly formatted.") + display("This share is incorrectly formatted. Reason: {}", reason) + } + + ShareParsingErrorEmptyShare(share_id: u8) { + description("This share is empty.") + display("Found empty share for share identifier ({})", share_id) + } + + ShareParsingInvalidShareId(share_id: u8) { + description("Invalid share identifier.") + display("Found invalid share identifier ({})", share_id) + } + + InvalidSS1Parameters(r: usize, s: usize) { + description("Invalid parameters for the SS1 sharing scheme") + display("Invalid parameters for the SS1 sharing scheme: r = {}, s = {}.", r, s) + } + + InvalidSplitParametersZero(k: u8, n: u8) { + description("Parameters k and n must be greater than zero") + display("Parameters k and n must be greater than zero.") + } + + #[cfg(feature = "dss")] + MismatchingShares(got: ss1::Share, expected: ss1::Share) { + description("Share mismatch during verification of secret recovery") + display("Share mismatch during verification of secret recovery.") + } + + CannotGenerateRandomNumbers { + description("Cannot generate random numbers") + display("Cannot generate random numbers.") + } + + DuplicateShareId(share_id: u8) { + description("This share number has already been used by a previous share.") + display("This share number ({}) has already been used by a previous share.", share_id) + } + + DuplicateShareData(share_id: u8) { + description("The data encoded in this share is the same as the one found in a previous share") + display("The data encoded in share #{} is the same as the one found in a previous share.", share_id) + } + + InconsistentShares { + description("The shares are inconsistent") + display("The shares are inconsistent") + } + } + + foreign_links { + Io(::std::io::Error); + IntegerParsingError(::std::num::ParseIntError); + } +} diff --git a/src/gf256.rs b/src/gf256.rs index ada62c5..e491146 100644 --- a/src/gf256.rs +++ b/src/gf256.rs @@ -1,7 +1,7 @@ //! This module provides the Gf256 type which is used to represent //! elements of a finite field with 256 elements. -use std::ops::{Add, Div, Mul, Sub}; +use std::ops::{Add, Div, Mul, Neg, Sub}; include!(concat!(env!("OUT_DIR"), "/nothinghardcoded.rs")); @@ -10,7 +10,7 @@ fn get_tables() -> &'static Tables { } /// Type for elements of a finite field with 256 elements -#[derive(Copy,Clone,PartialEq,Eq)] +#[derive(Copy, Debug, Clone, PartialEq, Eq)] pub struct Gf256 { pub poly: u8, } @@ -34,6 +34,10 @@ impl Gf256 { pub fn to_byte(&self) -> u8 { self.poly } + pub fn exp(power: u8) -> Gf256 { + let tabs = get_tables(); + Gf256::from_byte(tabs.exp[power as usize]) + } pub fn log(&self) -> Option { if self.poly == 0 { None @@ -42,9 +46,23 @@ impl Gf256 { Some(tabs.log[self.poly as usize]) } } - pub fn exp(power: u8) -> Gf256 { - let tabs = get_tables(); - Gf256 { poly: tabs.exp[power as usize] } + pub fn pow(&self, mut exp: u8) -> Gf256 { + let mut base = *self; + let mut acc = Self::one(); + + while exp > 1 { + if (exp & 1) == 1 { + acc = acc * base; + } + exp /= 2; + base = base * base; + } + + if exp == 1 { + acc = acc * base; + } + + acc } } @@ -68,7 +86,7 @@ impl Mul for Gf256 { type Output = Gf256; fn mul(self, rhs: Gf256) -> Gf256 { if let (Some(l1), Some(l2)) = (self.log(), rhs.log()) { - let tmp = ((l1 as u16) + (l2 as u16)) % 255; + let tmp = (u16::from(l1) + u16::from(l2)) % 255; Gf256::exp(tmp as u8) } else { Gf256 { poly: 0 } @@ -81,10 +99,159 @@ impl Div for Gf256 { fn div(self, rhs: Gf256) -> Gf256 { let l2 = rhs.log().expect("division by zero"); if let Some(l1) = self.log() { - let tmp = ((l1 as u16) + 255 - (l2 as u16)) % 255; + let tmp = (u16::from(l1) + 255 - u16::from(l2)) % 255; Gf256::exp(tmp as u8) } else { Gf256 { poly: 0 } } } } + +impl Neg for Gf256 { + type Output = Gf256; + fn neg(self) -> Gf256 { + Gf256::zero() - self + } +} + +#[macro_export] +#[doc(hidden)] +macro_rules! gf256 { + ($e:expr) => (Gf256::from_byte($e)) +} + +#[macro_export] +#[doc(hidden)] +macro_rules! gf256_vec { + ( $( ($x:expr, $y:expr) ),* ) => { + { + let mut temp_vec = Vec::new(); + $( + temp_vec.push((Gf256::from_byte($x), Gf256::from_byte($y))); + )* + temp_vec + } + }; + ( $( $x:expr ),* ) => { + { + let mut temp_vec = Vec::new(); + $( + temp_vec.push(Gf256::from_byte($x)); + )* + temp_vec + } + }; +} + +#[cfg(test)] +#[allow(trivial_casts)] +mod tests { + + use super::*; + use quickcheck::*; + + mod vectors { + use super::*; + use std::fs::File; + use std::io::{BufRead, BufReader}; + use itertools::Itertools; + use flate2::read::GzDecoder; + + macro_rules! mk_test { + ($id:ident, $op:expr, $val:expr) => { + mk_test!($id, $op, $val, 0); + }; + ($id:ident, $op:expr, $val:expr, $y:expr) => { + #[test] + fn $id() { + let results = (0..256).cartesian_product($y..256).map(|(i, j)| { + let (i, j) = (Gf256::from_byte(i as u8), Gf256::from_byte(j as u8)); + (i.to_byte(), j.to_byte(), $val(i, j).to_byte()) + }); + + let ref_path = format!("tests/fixtures/gf256/gf256_{}.txt.gz", stringify!($id)); + let reference = BufReader::new(GzDecoder::new(File::open(ref_path).unwrap()).unwrap()); + + for ((i, j, k), line) in results.zip(reference.lines()) { + let left = format!("{} {} {} = {}", i, $op, j, k); + let right = line.unwrap(); + assert_eq!(left, right); + } + } + } + } + + mk_test!(add, "+", |i: Gf256, j: Gf256| i + j); + mk_test!(sub, "-", |i: Gf256, j: Gf256| i - j); + mk_test!(mul, "*", |i: Gf256, j: Gf256| i * j); + mk_test!(div, "/", |i: Gf256, j: Gf256| i.div(j), 1); + mk_test!(pow, "^", |i: Gf256, j: Gf256| i.pow(j.to_byte())); + } + + impl Arbitrary for Gf256 { + fn arbitrary(gen: &mut G) -> Gf256 { + Gf256::from_byte(u8::arbitrary(gen)) + } + } + + mod addition { + use super::*; + + quickcheck! { + fn law_associativity(a: Gf256, b: Gf256, c: Gf256) -> bool { + (a + b) + c == a + (b + c) + } + + fn law_commutativity(a: Gf256, b: Gf256) -> bool { + a + b == b + a + } + + fn law_distributivity(a: Gf256, b: Gf256, c: Gf256) -> bool { + a * (b + c) == a * b + a * c + } + + fn law_identity(a: Gf256) -> bool { + a + Gf256::zero() == a && Gf256::zero() + a == a + } + + fn law_inverses(a: Gf256) -> bool { + a + (-a) == Gf256::zero() && (-a) + a == Gf256::zero() + } + } + } + + mod multiplication { + use super::*; + + quickcheck! { + fn law_associativity(a: Gf256, b: Gf256, c: Gf256) -> bool { + (a * b) * c == a * (b * c) + } + + fn law_commutativity(a: Gf256, b: Gf256) -> bool { + a * b == b * a + } + + fn law_distributivity(a: Gf256, b: Gf256, c: Gf256) -> bool { + (a + b) * c == a * c + b * c + } + + fn law_identity(a: Gf256) -> bool { + a * Gf256::one() == a && Gf256::one() * a == a + } + + fn law_inverses(a: Gf256) -> TestResult { + if a == Gf256::zero() { + return TestResult::discard(); + } + + let left = a * (Gf256::one() / a) == Gf256::one(); + let right = (Gf256::one() / a) * a == Gf256::one(); + + TestResult::from_bool(left && right) + } + } + + } + +} diff --git a/src/interpolation.rs b/src/interpolation.rs deleted file mode 100644 index 6246ac1..0000000 --- a/src/interpolation.rs +++ /dev/null @@ -1,40 +0,0 @@ -use gf256::Gf256; -use std::io; -use std::io::prelude::*; - -/// evaluates a polynomial at x=1, 2, 3, ... n (inclusive) -pub fn encode(src: &[u8], n: u8, w: &mut W) -> io::Result<()> { - for raw_x in 1..((n as u16) + 1) { - let x = Gf256::from_byte(raw_x as u8); - let mut fac = Gf256::one(); - let mut acc = Gf256::zero(); - for &coeff in src.iter() { - acc = acc + fac * Gf256::from_byte(coeff); - fac = fac * x; - } - try!(w.write(&[acc.to_byte()])); - } - Ok(()) -} - -/// evaluates an interpolated polynomial at `Gf256::zero()` where -/// the polynomial is determined using Lagrangian interpolation -/// based on the given x/y coordinates `src`. -pub fn lagrange_interpolate(src: &[(u8, u8)]) -> u8 { - let mut sum = Gf256::zero(); - for (i, &(raw_xi, raw_yi)) in src.iter().enumerate() { - let xi = Gf256::from_byte(raw_xi); - let yi = Gf256::from_byte(raw_yi); - let mut prod = Gf256::one(); - for (j, &(raw_xj, _)) in src.iter().enumerate() { - if i != j { - let xj = Gf256::from_byte(raw_xj); - let delta = xi - xj; - assert!(delta.poly != 0, "Duplicate shares"); - prod = prod * xj / delta; - } - } - sum = sum + prod * yi; - } - sum.to_byte() -} diff --git a/src/lagrange.rs b/src/lagrange.rs new file mode 100644 index 0000000..9142372 --- /dev/null +++ b/src/lagrange.rs @@ -0,0 +1,124 @@ +use gf256::Gf256; +use poly::Poly; + +/// Evaluates an interpolated polynomial at `Gf256::zero()` where +/// the polynomial is determined using Lagrangian interpolation +/// based on the given `points` in the G(2^8) Galois field. +pub(crate) fn interpolate_at(points: &[(u8, u8)]) -> u8 { + let mut sum = Gf256::zero(); + for (i, &(raw_xi, raw_yi)) in points.iter().enumerate() { + let xi = Gf256::from_byte(raw_xi); + let yi = Gf256::from_byte(raw_yi); + let mut prod = Gf256::one(); + for (j, &(raw_xj, _)) in points.iter().enumerate() { + if i != j { + let xj = Gf256::from_byte(raw_xj); + let delta = xi - xj; + assert_ne!(delta.poly, 0, "Duplicate shares"); + prod = prod * xj / delta; + } + } + sum = sum + prod * yi; + } + sum.to_byte() +} + +/// Computeds the coefficient of the Lagrange polynomial interpolated +/// from the given `points`, in the G(2^8) Galois field. +pub(crate) fn interpolate(points: &[(Gf256, Gf256)]) -> Poly { + let len = points.len(); + + let mut poly = vec![Gf256::zero(); len]; + + for &(x, y) in points { + let mut coeffs = vec![Gf256::zero(); len]; + coeffs[0] = y; + + let mut prod = Gf256::one(); + for &(x1, _) in points { + if x != x1 { + prod = prod * (x - x1); + + let mut prec = Gf256::zero(); + coeffs = coeffs + .into_iter() + .map(|coeff| { + let new_coeff = coeff * (-x1) + prec; + prec = coeff; + new_coeff + }) + .collect(); + } + } + + poly = poly.iter() + .zip(coeffs.iter()) + .map(|(&old_coeff, &add)| old_coeff + add / prod) + .collect(); + } + + Poly::new(poly) +} + +#[cfg(test)] +#[allow(trivial_casts)] +mod tests { + + use std; + use super::*; + use gf256::*; + use quickcheck::*; + + quickcheck! { + + fn evaluate_at_works(ys: Vec) -> TestResult { + if ys.is_empty() || ys.len() > std::u8::MAX as usize { + return TestResult::discard(); + } + + let points = ys.iter().enumerate().map(|(x, y)| (x as u8, *y)).collect::>(); + let equals = interpolate_at(points.as_slice()) == ys[0]; + + TestResult::from_bool(equals) + } + + + fn interpolate_evaluate_at_works(ys: Vec) -> TestResult { + if ys.is_empty() || ys.len() > std::u8::MAX as usize { + return TestResult::discard(); + } + + let points = ys.into_iter().enumerate().map(|(x, y)| (gf256!(x as u8), y)).collect::>(); + let poly = interpolate(&points); + + for (x, y) in points { + if poly.evaluate_at(x) != y { + return TestResult::failed(); + } + } + + TestResult::passed() + } + + fn interpolate_evaluate_at_0_eq_evaluate_at(ys: Vec) -> TestResult { + if ys.len() > std::u8::MAX as usize { + return TestResult::discard(); + } + + let points = ys.into_iter().enumerate().map(|(x, y)| (x as u8, y)).collect::>(); + + let elems = points + .iter() + .map(|&(x, y)| (gf256!(x), gf256!(y))) + .collect::>(); + + let poly = interpolate(&elems); + + let equals = poly.evaluate_at(Gf256::zero()).to_byte() == interpolate_at(points.as_slice()); + + TestResult::from_bool(equals) + } + + } + +} diff --git a/src/lib.rs b/src/lib.rs index 42a2bf9..4b88428 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,37 +1,42 @@ //! `RustySecrets` implements Shamir's secret sharing in Rust. It provides the possibility to sign shares. -#![deny( - missing_docs, - missing_debug_implementations, missing_copy_implementations, - trivial_casts, trivial_numeric_casts, - unsafe_code, unstable_features, - unused_import_braces, unused_qualifications -)] +#![deny(missing_docs, missing_debug_implementations, missing_copy_implementations, trivial_casts, + trivial_numeric_casts, unsafe_code, unstable_features, unused_import_braces, + unused_qualifications)] +#![cfg_attr(feature = "cargo-clippy", allow(doc_markdown))] +// `error_chain!` can recurse deeply +#![recursion_limit = "1024"] -extern crate protobuf; -extern crate rustc_serialize as serialize; -extern crate rand; +#[macro_use] +extern crate error_chain; + +extern crate base64; extern crate merkle_sigs; +extern crate protobuf; +extern crate rand; extern crate ring; -use ring::digest::{Algorithm, SHA512}; -#[allow(non_upper_case_globals)] -static digest: &'static Algorithm = &SHA512; - -mod custom_error; +#[macro_use] mod gf256; -mod interpolation; -#[allow(unused_qualifications)] -mod secret; -#[allow(unused_qualifications)] -mod share_data; -mod share_format; -mod validation; - -pub use custom_error::RustyError; +mod share; +mod poly; +mod lagrange; +mod vol_hash; +pub mod errors; pub mod sss; pub mod wrapped_secrets; +pub mod proto; + +#[cfg(feature = "dss")] +pub mod dss; #[cfg(test)] -mod tests; +extern crate itertools; + +#[cfg(test)] +extern crate flate2; + +#[cfg(test)] +#[macro_use] +extern crate quickcheck; diff --git a/src/poly.rs b/src/poly.rs new file mode 100644 index 0000000..be8bf95 --- /dev/null +++ b/src/poly.rs @@ -0,0 +1,29 @@ +use gf256::Gf256; + +static MAX_COEFFS: usize = 256; + +pub(crate) struct Poly { + pub coeffs: Vec, +} + +impl Poly { + pub fn new(coeffs: Vec) -> Self { + Self { coeffs } + } + + pub fn evaluate_at_zero(&self) -> Gf256 { + self.coeffs[0] + } + + pub fn evaluate_at(&self, x: Gf256) -> Gf256 { + assert!(self.coeffs.len() < MAX_COEFFS); + + let mut result = Gf256::zero(); + + for (i, c) in self.coeffs.iter().enumerate() { + result = result + *c * x.pow(i as u8); + } + + result + } +} diff --git a/src/proto/dss/metadata.rs b/src/proto/dss/metadata.rs new file mode 100644 index 0000000..0b27f5d --- /dev/null +++ b/src/proto/dss/metadata.rs @@ -0,0 +1,253 @@ +// This file is generated. Do not edit +// @generated + +// https://github.com/Manishearth/rust-clippy/issues/702 +#![allow(unknown_lints)] +#![allow(clippy)] + +#![cfg_attr(rustfmt, rustfmt_skip)] + +#![allow(box_pointers)] +#![allow(dead_code)] +#![allow(missing_docs)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(trivial_casts)] +#![allow(unsafe_code)] +#![allow(unused_imports)] +#![allow(unused_results)] + +use protobuf::Message as Message_imported_for_functions; +use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions; + +#[derive(PartialEq, Clone, Default)] +pub struct MetaDataProto { + // message fields + pub tags: ::std::collections::HashMap<::std::string::String, ::std::string::String>, + // special fields + unknown_fields: ::protobuf::UnknownFields, + cached_size: ::protobuf::CachedSize, +} + +// see codegen.rs for the explanation why impl Sync explicitly +unsafe impl ::std::marker::Sync for MetaDataProto {} + +impl MetaDataProto { + pub fn new() -> MetaDataProto { + ::std::default::Default::default() + } + + pub fn default_instance() -> &'static MetaDataProto { + static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const MetaDataProto, + }; + unsafe { instance.get(MetaDataProto::new) } + } + + // repeated .dss.MetaDataProto.TagsEntry tags = 1; + + pub fn clear_tags(&mut self) { + self.tags.clear(); + } + + // Param is passed by value, moved + pub fn set_tags( + &mut self, + v: ::std::collections::HashMap<::std::string::String, ::std::string::String>, + ) { + self.tags = v; + } + + // Mutable pointer to the field. + pub fn mut_tags( + &mut self, + ) -> &mut ::std::collections::HashMap<::std::string::String, ::std::string::String> { + &mut self.tags + } + + // Take field + pub fn take_tags( + &mut self, + ) -> ::std::collections::HashMap<::std::string::String, ::std::string::String> { + ::std::mem::replace(&mut self.tags, ::std::collections::HashMap::new()) + } + + pub fn get_tags( + &self, + ) -> &::std::collections::HashMap<::std::string::String, ::std::string::String> { + &self.tags + } + + fn get_tags_for_reflect( + &self, + ) -> &::std::collections::HashMap<::std::string::String, ::std::string::String> { + &self.tags + } + + fn mut_tags_for_reflect( + &mut self, + ) -> &mut ::std::collections::HashMap<::std::string::String, ::std::string::String> { + &mut self.tags + } +} + +impl ::protobuf::Message for MetaDataProto { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from( + &mut self, + is: &mut ::protobuf::CodedInputStream, + ) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_map_into::< + ::protobuf::types::ProtobufTypeString, + ::protobuf::types::ProtobufTypeString, + >(wire_type, is, &mut self.tags)?; + } + _ => { + ::protobuf::rt::read_unknown_or_skip_group( + field_number, + wire_type, + is, + self.mut_unknown_fields(), + )?; + } + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + my_size += ::protobuf::rt::compute_map_size::< + ::protobuf::types::ProtobufTypeString, + ::protobuf::types::ProtobufTypeString, + >(1, &self.tags); + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes( + &self, + os: &mut ::protobuf::CodedOutputStream, + ) -> ::protobuf::ProtobufResult<()> { + ::protobuf::rt::write_map_with_cached_sizes::< + ::protobuf::types::ProtobufTypeString, + ::protobuf::types::ProtobufTypeString, + >(1, &self.tags, os)?; + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &::std::any::Any { + self as &::std::any::Any + } + fn as_any_mut(&mut self) -> &mut ::std::any::Any { + self as &mut ::std::any::Any + } + fn into_any(self: Box) -> ::std::boxed::Box<::std::any::Any> { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + ::protobuf::MessageStatic::descriptor_static(None::) + } +} + +impl ::protobuf::MessageStatic for MetaDataProto { + fn new() -> MetaDataProto { + MetaDataProto::new() + } + + fn descriptor_static( + _: ::std::option::Option, + ) -> &'static ::protobuf::reflect::MessageDescriptor { + static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = + ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, + }; + unsafe { + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_map_accessor::<_, ::protobuf::types::ProtobufTypeString, ::protobuf::types::ProtobufTypeString>( + "tags", + MetaDataProto::get_tags_for_reflect, + MetaDataProto::mut_tags_for_reflect, + )); + ::protobuf::reflect::MessageDescriptor::new::( + "MetaDataProto", + fields, + file_descriptor_proto() + ) + }) + } + } +} + +impl ::protobuf::Clear for MetaDataProto { + fn clear(&mut self) { + self.clear_tags(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for MetaDataProto { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for MetaDataProto { + fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { + ::protobuf::reflect::ProtobufValueRef::Message(self) + } +} + +static file_descriptor_proto_data: &'static [u8] = b"\ + \n\x12dss/metadata.proto\x12\x03dss\"z\n\rMetaDataProto\x120\n\x04tags\ + \x18\x01\x20\x03(\x0b2\x1c.dss.MetaDataProto.TagsEntryR\x04tags\x1a7\n\t\ + TagsEntry\x12\x10\n\x03key\x18\x01\x20\x01(\tR\x03key\x12\x14\n\x05value\ + \x18\x02\x20\x01(\tR\x05value:\x028\x01Jz\n\x06\x12\x04\0\0\x06\x01\n\ + \x08\n\x01\x0c\x12\x03\0\0\x12\n\x08\n\x01\x02\x12\x03\x02\x08\x0b\n\n\n\ + \x02\x04\0\x12\x04\x04\0\x06\x01\n\n\n\x03\x04\0\x01\x12\x03\x04\x08\x15\ + \n\x0b\n\x04\x04\0\x02\0\x12\x03\x05\x02\x1f\n\r\n\x05\x04\0\x02\0\x04\ + \x12\x04\x05\x02\x04\x17\n\x0c\n\x05\x04\0\x02\0\x06\x12\x03\x05\x02\x15\ + \n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x05\x16\x1a\n\x0c\n\x05\x04\0\x02\0\ + \x03\x12\x03\x05\x1d\x1eb\x06proto3\ +"; + +static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::descriptor::FileDescriptorProto, +}; + +fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { + ::protobuf::parse_from_bytes(file_descriptor_proto_data).unwrap() +} + +pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { + unsafe { file_descriptor_proto_lazy.get(|| parse_descriptor_proto()) } +} diff --git a/src/proto/dss/mod.rs b/src/proto/dss/mod.rs new file mode 100644 index 0000000..e0d5214 --- /dev/null +++ b/src/proto/dss/mod.rs @@ -0,0 +1,13 @@ +#[allow(unused_qualifications, deprecated, missing_docs)] +mod secret; +pub use self::secret::SecretProto; + +#[allow(unused_qualifications, deprecated, missing_docs)] +mod share; +pub use self::share::ShareProto; + +#[allow(unused_qualifications, deprecated, missing_docs)] +mod metadata; +pub use self::metadata::MetaDataProto; + +pub use super::version; diff --git a/src/proto/dss/secret.rs b/src/proto/dss/secret.rs new file mode 100644 index 0000000..7b7a4c0 --- /dev/null +++ b/src/proto/dss/secret.rs @@ -0,0 +1,369 @@ +// This file is generated. Do not edit +// @generated + +// https://github.com/Manishearth/rust-clippy/issues/702 +#![allow(unknown_lints)] +#![allow(clippy)] + +#![cfg_attr(rustfmt, rustfmt_skip)] + +#![allow(box_pointers)] +#![allow(dead_code)] +#![allow(missing_docs)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(trivial_casts)] +#![allow(unsafe_code)] +#![allow(unused_imports)] +#![allow(unused_results)] + +use protobuf::Message as Message_imported_for_functions; +use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions; + +#[derive(PartialEq, Clone, Default)] +pub struct SecretProto { + // message fields + pub version: super::version::VersionProto, + pub secret: ::std::vec::Vec, + pub meta_data: ::protobuf::SingularPtrField, + // special fields + unknown_fields: ::protobuf::UnknownFields, + cached_size: ::protobuf::CachedSize, +} + +// see codegen.rs for the explanation why impl Sync explicitly +unsafe impl ::std::marker::Sync for SecretProto {} + +impl SecretProto { + pub fn new() -> SecretProto { + ::std::default::Default::default() + } + + pub fn default_instance() -> &'static SecretProto { + static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const SecretProto, + }; + unsafe { instance.get(SecretProto::new) } + } + + // .VersionProto version = 1; + + pub fn clear_version(&mut self) { + self.version = super::version::VersionProto::INITIAL_RELEASE; + } + + // Param is passed by value, moved + pub fn set_version(&mut self, v: super::version::VersionProto) { + self.version = v; + } + + pub fn get_version(&self) -> super::version::VersionProto { + self.version + } + + fn get_version_for_reflect(&self) -> &super::version::VersionProto { + &self.version + } + + fn mut_version_for_reflect(&mut self) -> &mut super::version::VersionProto { + &mut self.version + } + + // bytes secret = 2; + + pub fn clear_secret(&mut self) { + self.secret.clear(); + } + + // Param is passed by value, moved + pub fn set_secret(&mut self, v: ::std::vec::Vec) { + self.secret = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_secret(&mut self) -> &mut ::std::vec::Vec { + &mut self.secret + } + + // Take field + pub fn take_secret(&mut self) -> ::std::vec::Vec { + ::std::mem::replace(&mut self.secret, ::std::vec::Vec::new()) + } + + pub fn get_secret(&self) -> &[u8] { + &self.secret + } + + fn get_secret_for_reflect(&self) -> &::std::vec::Vec { + &self.secret + } + + fn mut_secret_for_reflect(&mut self) -> &mut ::std::vec::Vec { + &mut self.secret + } + + // .dss.MetaDataProto meta_data = 3; + + pub fn clear_meta_data(&mut self) { + self.meta_data.clear(); + } + + pub fn has_meta_data(&self) -> bool { + self.meta_data.is_some() + } + + // Param is passed by value, moved + pub fn set_meta_data(&mut self, v: super::metadata::MetaDataProto) { + self.meta_data = ::protobuf::SingularPtrField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_meta_data(&mut self) -> &mut super::metadata::MetaDataProto { + if self.meta_data.is_none() { + self.meta_data.set_default(); + } + self.meta_data.as_mut().unwrap() + } + + // Take field + pub fn take_meta_data(&mut self) -> super::metadata::MetaDataProto { + self.meta_data.take().unwrap_or_else(|| { + super::metadata::MetaDataProto::new() + }) + } + + pub fn get_meta_data(&self) -> &super::metadata::MetaDataProto { + self.meta_data.as_ref().unwrap_or_else(|| { + super::metadata::MetaDataProto::default_instance() + }) + } + + fn get_meta_data_for_reflect( + &self, + ) -> &::protobuf::SingularPtrField { + &self.meta_data + } + + fn mut_meta_data_for_reflect( + &mut self, + ) -> &mut ::protobuf::SingularPtrField { + &mut self.meta_data + } +} + +impl ::protobuf::Message for SecretProto { + fn is_initialized(&self) -> bool { + for v in &self.meta_data { + if !v.is_initialized() { + return false; + } + } + true + } + + fn merge_from( + &mut self, + is: &mut ::protobuf::CodedInputStream, + ) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err( + ::protobuf::rt::unexpected_wire_type(wire_type), + ); + } + let tmp = is.read_enum()?; + self.version = tmp; + } + 2 => { + ::protobuf::rt::read_singular_proto3_bytes_into( + wire_type, + is, + &mut self.secret, + )?; + } + 3 => { + ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.meta_data)?; + } + _ => { + ::protobuf::rt::read_unknown_or_skip_group( + field_number, + wire_type, + is, + self.mut_unknown_fields(), + )?; + } + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if self.version != super::version::VersionProto::INITIAL_RELEASE { + my_size += ::protobuf::rt::enum_size(1, self.version); + } + if !self.secret.is_empty() { + my_size += ::protobuf::rt::bytes_size(2, &self.secret); + } + if let Some(ref v) = self.meta_data.as_ref() { + let len = v.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes( + &self, + os: &mut ::protobuf::CodedOutputStream, + ) -> ::protobuf::ProtobufResult<()> { + if self.version != super::version::VersionProto::INITIAL_RELEASE { + os.write_enum(1, self.version.value())?; + } + if !self.secret.is_empty() { + os.write_bytes(2, &self.secret)?; + } + if let Some(ref v) = self.meta_data.as_ref() { + os.write_tag( + 3, + ::protobuf::wire_format::WireTypeLengthDelimited, + )?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &::std::any::Any { + self as &::std::any::Any + } + fn as_any_mut(&mut self) -> &mut ::std::any::Any { + self as &mut ::std::any::Any + } + fn into_any(self: Box) -> ::std::boxed::Box<::std::any::Any> { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + ::protobuf::MessageStatic::descriptor_static(None::) + } +} + +impl ::protobuf::MessageStatic for SecretProto { + fn new() -> SecretProto { + SecretProto::new() + } + + fn descriptor_static( + _: ::std::option::Option, + ) -> &'static ::protobuf::reflect::MessageDescriptor { + static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = + ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, + }; + unsafe { + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum>( + "version", + SecretProto::get_version_for_reflect, + SecretProto::mut_version_for_reflect, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( + "secret", + SecretProto::get_secret_for_reflect, + SecretProto::mut_secret_for_reflect, + )); + fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "meta_data", + SecretProto::get_meta_data_for_reflect, + SecretProto::mut_meta_data_for_reflect, + )); + ::protobuf::reflect::MessageDescriptor::new::( + "SecretProto", + fields, + file_descriptor_proto() + ) + }) + } + } +} + +impl ::protobuf::Clear for SecretProto { + fn clear(&mut self) { + self.clear_version(); + self.clear_secret(); + self.clear_meta_data(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for SecretProto { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for SecretProto { + fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { + ::protobuf::reflect::ProtobufValueRef::Message(self) + } +} + +static file_descriptor_proto_data: &'static [u8] = b"\ + \n\x10dss/secret.proto\x1a\rversion.proto\x1a\x12dss/metadata.proto\"\ + \x7f\n\x0bSecretProto\x12'\n\x07version\x18\x01\x20\x01(\x0e2\r.VersionP\ + rotoR\x07version\x12\x16\n\x06secret\x18\x02\x20\x01(\x0cR\x06secret\x12\ + /\n\tmeta_data\x18\x03\x20\x01(\x0b2\x12.dss.MetaDataProtoR\x08metaDataJ\ + \x92\x02\n\x06\x12\x04\0\0\t\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\t\n\ + \x02\x03\0\x12\x03\x02\x07\x16\n\t\n\x02\x03\x01\x12\x03\x03\x07\x1b\n\n\ + \n\x02\x04\0\x12\x04\x05\0\t\x01\n\n\n\x03\x04\0\x01\x12\x03\x05\x08\x13\ + \n\x0b\n\x04\x04\0\x02\0\x12\x03\x06\x08!\n\r\n\x05\x04\0\x02\0\x04\x12\ + \x04\x06\x08\x05\x15\n\x0c\n\x05\x04\0\x02\0\x06\x12\x03\x06\x08\x14\n\ + \x0c\n\x05\x04\0\x02\0\x01\x12\x03\x06\x15\x1c\n\x0c\n\x05\x04\0\x02\0\ + \x03\x12\x03\x06\x1f\x20\n\x0b\n\x04\x04\0\x02\x01\x12\x03\x07\x08\x19\n\ + \r\n\x05\x04\0\x02\x01\x04\x12\x04\x07\x08\x06!\n\x0c\n\x05\x04\0\x02\ + \x01\x05\x12\x03\x07\x08\r\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x07\x0e\ + \x14\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x07\x17\x18\n\x0b\n\x04\x04\0\ + \x02\x02\x12\x03\x08\x08(\n\r\n\x05\x04\0\x02\x02\x04\x12\x04\x08\x08\ + \x07\x19\n\x0c\n\x05\x04\0\x02\x02\x06\x12\x03\x08\x08\x19\n\x0c\n\x05\ + \x04\0\x02\x02\x01\x12\x03\x08\x1a#\n\x0c\n\x05\x04\0\x02\x02\x03\x12\ + \x03\x08&'b\x06proto3\ +"; + +static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::descriptor::FileDescriptorProto, +}; + +fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { + ::protobuf::parse_from_bytes(file_descriptor_proto_data).unwrap() +} + +pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { + unsafe { file_descriptor_proto_lazy.get(|| parse_descriptor_proto()) } +} diff --git a/src/proto/dss/share.rs b/src/proto/dss/share.rs new file mode 100644 index 0000000..4eb8e40 --- /dev/null +++ b/src/proto/dss/share.rs @@ -0,0 +1,492 @@ +// This file is generated. Do not edit +// @generated + +// https://github.com/Manishearth/rust-clippy/issues/702 +#![allow(unknown_lints)] +#![allow(clippy)] + +#![cfg_attr(rustfmt, rustfmt_skip)] + +#![allow(box_pointers)] +#![allow(dead_code)] +#![allow(missing_docs)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(trivial_casts)] +#![allow(unsafe_code)] +#![allow(unused_imports)] +#![allow(unused_results)] + +use protobuf::Message as Message_imported_for_functions; +use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions; + +#[derive(PartialEq,Clone,Default)] +pub struct ShareProto { + // message fields + pub id: u32, + pub threshold: u32, + pub shares_count: u32, + pub data: ::std::vec::Vec, + pub hash: ::std::vec::Vec, + pub meta_data: ::protobuf::SingularPtrField, + // special fields + unknown_fields: ::protobuf::UnknownFields, + cached_size: ::protobuf::CachedSize, +} + +// see codegen.rs for the explanation why impl Sync explicitly +unsafe impl ::std::marker::Sync for ShareProto {} + +impl ShareProto { + pub fn new() -> ShareProto { + ::std::default::Default::default() + } + + pub fn default_instance() -> &'static ShareProto { + static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ShareProto, + }; + unsafe { + instance.get(ShareProto::new) + } + } + + // uint32 id = 1; + + pub fn clear_id(&mut self) { + self.id = 0; + } + + // Param is passed by value, moved + pub fn set_id(&mut self, v: u32) { + self.id = v; + } + + pub fn get_id(&self) -> u32 { + self.id + } + + fn get_id_for_reflect(&self) -> &u32 { + &self.id + } + + fn mut_id_for_reflect(&mut self) -> &mut u32 { + &mut self.id + } + + // uint32 threshold = 2; + + pub fn clear_threshold(&mut self) { + self.threshold = 0; + } + + // Param is passed by value, moved + pub fn set_threshold(&mut self, v: u32) { + self.threshold = v; + } + + pub fn get_threshold(&self) -> u32 { + self.threshold + } + + fn get_threshold_for_reflect(&self) -> &u32 { + &self.threshold + } + + fn mut_threshold_for_reflect(&mut self) -> &mut u32 { + &mut self.threshold + } + + // uint32 shares_count = 3; + + pub fn clear_shares_count(&mut self) { + self.shares_count = 0; + } + + // Param is passed by value, moved + pub fn set_shares_count(&mut self, v: u32) { + self.shares_count = v; + } + + pub fn get_shares_count(&self) -> u32 { + self.shares_count + } + + fn get_shares_count_for_reflect(&self) -> &u32 { + &self.shares_count + } + + fn mut_shares_count_for_reflect(&mut self) -> &mut u32 { + &mut self.shares_count + } + + // bytes data = 4; + + pub fn clear_data(&mut self) { + self.data.clear(); + } + + // Param is passed by value, moved + pub fn set_data(&mut self, v: ::std::vec::Vec) { + self.data = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_data(&mut self) -> &mut ::std::vec::Vec { + &mut self.data + } + + // Take field + pub fn take_data(&mut self) -> ::std::vec::Vec { + ::std::mem::replace(&mut self.data, ::std::vec::Vec::new()) + } + + pub fn get_data(&self) -> &[u8] { + &self.data + } + + fn get_data_for_reflect(&self) -> &::std::vec::Vec { + &self.data + } + + fn mut_data_for_reflect(&mut self) -> &mut ::std::vec::Vec { + &mut self.data + } + + // bytes hash = 5; + + pub fn clear_hash(&mut self) { + self.hash.clear(); + } + + // Param is passed by value, moved + pub fn set_hash(&mut self, v: ::std::vec::Vec) { + self.hash = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_hash(&mut self) -> &mut ::std::vec::Vec { + &mut self.hash + } + + // Take field + pub fn take_hash(&mut self) -> ::std::vec::Vec { + ::std::mem::replace(&mut self.hash, ::std::vec::Vec::new()) + } + + pub fn get_hash(&self) -> &[u8] { + &self.hash + } + + fn get_hash_for_reflect(&self) -> &::std::vec::Vec { + &self.hash + } + + fn mut_hash_for_reflect(&mut self) -> &mut ::std::vec::Vec { + &mut self.hash + } + + // .dss.MetaDataProto meta_data = 6; + + pub fn clear_meta_data(&mut self) { + self.meta_data.clear(); + } + + pub fn has_meta_data(&self) -> bool { + self.meta_data.is_some() + } + + // Param is passed by value, moved + pub fn set_meta_data(&mut self, v: super::metadata::MetaDataProto) { + self.meta_data = ::protobuf::SingularPtrField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_meta_data(&mut self) -> &mut super::metadata::MetaDataProto { + if self.meta_data.is_none() { + self.meta_data.set_default(); + } + self.meta_data.as_mut().unwrap() + } + + // Take field + pub fn take_meta_data(&mut self) -> super::metadata::MetaDataProto { + self.meta_data.take().unwrap_or_else(|| super::metadata::MetaDataProto::new()) + } + + pub fn get_meta_data(&self) -> &super::metadata::MetaDataProto { + self.meta_data.as_ref().unwrap_or_else(|| super::metadata::MetaDataProto::default_instance()) + } + + fn get_meta_data_for_reflect(&self) -> &::protobuf::SingularPtrField { + &self.meta_data + } + + fn mut_meta_data_for_reflect(&mut self) -> &mut ::protobuf::SingularPtrField { + &mut self.meta_data + } +} + +impl ::protobuf::Message for ShareProto { + fn is_initialized(&self) -> bool { + for v in &self.meta_data { + if !v.is_initialized() { + return false; + } + }; + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_uint32()?; + self.id = tmp; + }, + 2 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_uint32()?; + self.threshold = tmp; + }, + 3 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_uint32()?; + self.shares_count = tmp; + }, + 4 => { + ::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.data)?; + }, + 5 => { + ::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.hash)?; + }, + 6 => { + ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.meta_data)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if self.id != 0 { + my_size += ::protobuf::rt::value_size(1, self.id, ::protobuf::wire_format::WireTypeVarint); + } + if self.threshold != 0 { + my_size += ::protobuf::rt::value_size(2, self.threshold, ::protobuf::wire_format::WireTypeVarint); + } + if self.shares_count != 0 { + my_size += ::protobuf::rt::value_size(3, self.shares_count, ::protobuf::wire_format::WireTypeVarint); + } + if !self.data.is_empty() { + my_size += ::protobuf::rt::bytes_size(4, &self.data); + } + if !self.hash.is_empty() { + my_size += ::protobuf::rt::bytes_size(5, &self.hash); + } + if let Some(ref v) = self.meta_data.as_ref() { + let len = v.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + if self.id != 0 { + os.write_uint32(1, self.id)?; + } + if self.threshold != 0 { + os.write_uint32(2, self.threshold)?; + } + if self.shares_count != 0 { + os.write_uint32(3, self.shares_count)?; + } + if !self.data.is_empty() { + os.write_bytes(4, &self.data)?; + } + if !self.hash.is_empty() { + os.write_bytes(5, &self.hash)?; + } + if let Some(ref v) = self.meta_data.as_ref() { + os.write_tag(6, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &::std::any::Any { + self as &::std::any::Any + } + fn as_any_mut(&mut self) -> &mut ::std::any::Any { + self as &mut ::std::any::Any + } + fn into_any(self: Box) -> ::std::boxed::Box<::std::any::Any> { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + ::protobuf::MessageStatic::descriptor_static(None::) + } +} + +impl ::protobuf::MessageStatic for ShareProto { + fn new() -> ShareProto { + ShareProto::new() + } + + fn descriptor_static(_: ::std::option::Option) -> &'static ::protobuf::reflect::MessageDescriptor { + static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, + }; + unsafe { + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeUint32>( + "id", + ShareProto::get_id_for_reflect, + ShareProto::mut_id_for_reflect, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeUint32>( + "threshold", + ShareProto::get_threshold_for_reflect, + ShareProto::mut_threshold_for_reflect, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeUint32>( + "shares_count", + ShareProto::get_shares_count_for_reflect, + ShareProto::mut_shares_count_for_reflect, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( + "data", + ShareProto::get_data_for_reflect, + ShareProto::mut_data_for_reflect, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( + "hash", + ShareProto::get_hash_for_reflect, + ShareProto::mut_hash_for_reflect, + )); + fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "meta_data", + ShareProto::get_meta_data_for_reflect, + ShareProto::mut_meta_data_for_reflect, + )); + ::protobuf::reflect::MessageDescriptor::new::( + "ShareProto", + fields, + file_descriptor_proto() + ) + }) + } + } +} + +impl ::protobuf::Clear for ShareProto { + fn clear(&mut self) { + self.clear_id(); + self.clear_threshold(); + self.clear_shares_count(); + self.clear_data(); + self.clear_hash(); + self.clear_meta_data(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for ShareProto { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for ShareProto { + fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { + ::protobuf::reflect::ProtobufValueRef::Message(self) + } +} + +static file_descriptor_proto_data: &'static [u8] = b"\ + \n\x0fdss/share.proto\x12\x03dss\x1a\x12dss/metadata.proto\"\xb6\x01\n\n\ + ShareProto\x12\x0e\n\x02id\x18\x01\x20\x01(\rR\x02id\x12\x1c\n\tthreshol\ + d\x18\x02\x20\x01(\rR\tthreshold\x12!\n\x0cshares_count\x18\x03\x20\x01(\ + \rR\x0bsharesCount\x12\x12\n\x04data\x18\x04\x20\x01(\x0cR\x04data\x12\ + \x12\n\x04hash\x18\x05\x20\x01(\x0cR\x04hash\x12/\n\tmeta_data\x18\x06\ + \x20\x01(\x0b2\x12.dss.MetaDataProtoR\x08metaDataJ\xe3\x03\n\x06\x12\x04\ + \0\0\r\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\x08\n\x01\x02\x12\x03\x02\ + \x08\x0b\n\t\n\x02\x03\0\x12\x03\x04\x07\x1b\n\n\n\x02\x04\0\x12\x04\x06\ + \0\r\x01\n\n\n\x03\x04\0\x01\x12\x03\x06\x08\x12\n\x0b\n\x04\x04\0\x02\0\ + \x12\x03\x07\x02\x10\n\r\n\x05\x04\0\x02\0\x04\x12\x04\x07\x02\x06\x14\n\ + \x0c\n\x05\x04\0\x02\0\x05\x12\x03\x07\x02\x08\n\x0c\n\x05\x04\0\x02\0\ + \x01\x12\x03\x07\t\x0b\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x07\x0e\x0f\n\ + \x0b\n\x04\x04\0\x02\x01\x12\x03\x08\x02\x17\n\r\n\x05\x04\0\x02\x01\x04\ + \x12\x04\x08\x02\x07\x10\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x08\x02\ + \x08\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x08\t\x12\n\x0c\n\x05\x04\0\ + \x02\x01\x03\x12\x03\x08\x15\x16\n\x0b\n\x04\x04\0\x02\x02\x12\x03\t\x02\ + \x1a\n\r\n\x05\x04\0\x02\x02\x04\x12\x04\t\x02\x08\x17\n\x0c\n\x05\x04\0\ + \x02\x02\x05\x12\x03\t\x02\x08\n\x0c\n\x05\x04\0\x02\x02\x01\x12\x03\t\t\ + \x15\n\x0c\n\x05\x04\0\x02\x02\x03\x12\x03\t\x18\x19\n\x0b\n\x04\x04\0\ + \x02\x03\x12\x03\n\x02\x11\n\r\n\x05\x04\0\x02\x03\x04\x12\x04\n\x02\t\ + \x1a\n\x0c\n\x05\x04\0\x02\x03\x05\x12\x03\n\x02\x07\n\x0c\n\x05\x04\0\ + \x02\x03\x01\x12\x03\n\x08\x0c\n\x0c\n\x05\x04\0\x02\x03\x03\x12\x03\n\ + \x0f\x10\n\x0b\n\x04\x04\0\x02\x04\x12\x03\x0b\x02\x11\n\r\n\x05\x04\0\ + \x02\x04\x04\x12\x04\x0b\x02\n\x11\n\x0c\n\x05\x04\0\x02\x04\x05\x12\x03\ + \x0b\x02\x07\n\x0c\n\x05\x04\0\x02\x04\x01\x12\x03\x0b\x08\x0c\n\x0c\n\ + \x05\x04\0\x02\x04\x03\x12\x03\x0b\x0f\x10\n\x0b\n\x04\x04\0\x02\x05\x12\ + \x03\x0c\x02\"\n\r\n\x05\x04\0\x02\x05\x04\x12\x04\x0c\x02\x0b\x11\n\x0c\ + \n\x05\x04\0\x02\x05\x06\x12\x03\x0c\x02\x13\n\x0c\n\x05\x04\0\x02\x05\ + \x01\x12\x03\x0c\x14\x1d\n\x0c\n\x05\x04\0\x02\x05\x03\x12\x03\x0c\x20!b\ + \x06proto3\ +"; + +static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::descriptor::FileDescriptorProto, +}; + +fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { + ::protobuf::parse_from_bytes(file_descriptor_proto_data).unwrap() +} + +pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { + unsafe { + file_descriptor_proto_lazy.get(|| { + parse_descriptor_proto() + }) + } +} diff --git a/src/proto/mod.rs b/src/proto/mod.rs new file mode 100644 index 0000000..11295a3 --- /dev/null +++ b/src/proto/mod.rs @@ -0,0 +1,12 @@ +//! Protocol buffer definitions + +#[allow(unused_qualifications, deprecated, missing_docs)] +pub mod wrapped; + +#[allow(unused_qualifications, deprecated, missing_docs)] +pub mod dss; + +#[doc(hidden)] +#[allow(unused_qualifications, deprecated, missing_docs)] +pub mod version; +pub use self::version::VersionProto; diff --git a/src/proto/version.rs b/src/proto/version.rs new file mode 100644 index 0000000..9680b35 --- /dev/null +++ b/src/proto/version.rs @@ -0,0 +1,100 @@ +// This file is generated. Do not edit +// @generated + +// https://github.com/Manishearth/rust-clippy/issues/702 +#![allow(unknown_lints)] +#![allow(clippy)] + +#![cfg_attr(rustfmt, rustfmt_skip)] + +#![allow(box_pointers)] +#![allow(dead_code)] +#![allow(missing_docs)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(trivial_casts)] +#![allow(unsafe_code)] +#![allow(unused_imports)] +#![allow(unused_results)] + +use protobuf::Message as Message_imported_for_functions; +use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions; + +#[derive(Clone,PartialEq,Eq,Debug,Hash)] +pub enum VersionProto { + INITIAL_RELEASE = 0, +} + +impl ::protobuf::ProtobufEnum for VersionProto { + fn value(&self) -> i32 { + *self as i32 + } + + fn from_i32(value: i32) -> ::std::option::Option { + match value { + 0 => ::std::option::Option::Some(VersionProto::INITIAL_RELEASE), + _ => ::std::option::Option::None + } + } + + fn values() -> &'static [Self] { + static values: &'static [VersionProto] = &[ + VersionProto::INITIAL_RELEASE, + ]; + values + } + + fn enum_descriptor_static(_: ::std::option::Option) -> &'static ::protobuf::reflect::EnumDescriptor { + static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::EnumDescriptor> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::reflect::EnumDescriptor, + }; + unsafe { + descriptor.get(|| { + ::protobuf::reflect::EnumDescriptor::new("VersionProto", file_descriptor_proto()) + }) + } + } +} + +impl ::std::marker::Copy for VersionProto { +} + +impl ::std::default::Default for VersionProto { + fn default() -> Self { + VersionProto::INITIAL_RELEASE + } +} + +impl ::protobuf::reflect::ProtobufValue for VersionProto { + fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { + ::protobuf::reflect::ProtobufValueRef::Enum(self.descriptor()) + } +} + +static file_descriptor_proto_data: &'static [u8] = b"\ + \n\rversion.proto*#\n\x0cVersionProto\x12\x13\n\x0fINITIAL_RELEASE\x10\0\ + JS\n\x06\x12\x04\x01\0\x05\x01\n\x08\n\x01\x0c\x12\x03\x01\0\x12\n\n\n\ + \x02\x05\0\x12\x04\x03\0\x05\x01\n\n\n\x03\x05\0\x01\x12\x03\x03\x05\x11\ + \n\x0b\n\x04\x05\0\x02\0\x12\x03\x04\x02\x16\n\x0c\n\x05\x05\0\x02\0\x01\ + \x12\x03\x04\x02\x11\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x04\x14\x15b\ + \x06proto3\ +"; + +static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::descriptor::FileDescriptorProto, +}; + +fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { + ::protobuf::parse_from_bytes(file_descriptor_proto_data).unwrap() +} + +pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { + unsafe { + file_descriptor_proto_lazy.get(|| { + parse_descriptor_proto() + }) + } +} diff --git a/src/proto/wrapped/mod.rs b/src/proto/wrapped/mod.rs new file mode 100644 index 0000000..1b0ef27 --- /dev/null +++ b/src/proto/wrapped/mod.rs @@ -0,0 +1,9 @@ +#[allow(unused_qualifications, deprecated, missing_docs)] +mod secret; +pub use self::secret::SecretProto; + +#[allow(unused_qualifications, deprecated, missing_docs)] +mod share; +pub use self::share::ShareProto; + +pub use super::version; diff --git a/src/proto/wrapped/secret.rs b/src/proto/wrapped/secret.rs new file mode 100644 index 0000000..3906856 --- /dev/null +++ b/src/proto/wrapped/secret.rs @@ -0,0 +1,328 @@ +// This file is generated. Do not edit +// @generated + +// https://github.com/Manishearth/rust-clippy/issues/702 +#![allow(unknown_lints)] +#![allow(clippy)] + +#![cfg_attr(rustfmt, rustfmt_skip)] + +#![allow(box_pointers)] +#![allow(dead_code)] +#![allow(missing_docs)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(trivial_casts)] +#![allow(unsafe_code)] +#![allow(unused_imports)] +#![allow(unused_results)] + +use protobuf::Message as Message_imported_for_functions; +use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions; + +#[derive(PartialEq,Clone,Default)] +pub struct SecretProto { + // message fields + pub version: super::version::VersionProto, + pub secret: ::std::vec::Vec, + pub mime_type: ::std::string::String, + // special fields + unknown_fields: ::protobuf::UnknownFields, + cached_size: ::protobuf::CachedSize, +} + +// see codegen.rs for the explanation why impl Sync explicitly +unsafe impl ::std::marker::Sync for SecretProto {} + +impl SecretProto { + pub fn new() -> SecretProto { + ::std::default::Default::default() + } + + pub fn default_instance() -> &'static SecretProto { + static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const SecretProto, + }; + unsafe { + instance.get(SecretProto::new) + } + } + + // .VersionProto version = 1; + + pub fn clear_version(&mut self) { + self.version = super::version::VersionProto::INITIAL_RELEASE; + } + + // Param is passed by value, moved + pub fn set_version(&mut self, v: super::version::VersionProto) { + self.version = v; + } + + pub fn get_version(&self) -> super::version::VersionProto { + self.version + } + + fn get_version_for_reflect(&self) -> &super::version::VersionProto { + &self.version + } + + fn mut_version_for_reflect(&mut self) -> &mut super::version::VersionProto { + &mut self.version + } + + // bytes secret = 2; + + pub fn clear_secret(&mut self) { + self.secret.clear(); + } + + // Param is passed by value, moved + pub fn set_secret(&mut self, v: ::std::vec::Vec) { + self.secret = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_secret(&mut self) -> &mut ::std::vec::Vec { + &mut self.secret + } + + // Take field + pub fn take_secret(&mut self) -> ::std::vec::Vec { + ::std::mem::replace(&mut self.secret, ::std::vec::Vec::new()) + } + + pub fn get_secret(&self) -> &[u8] { + &self.secret + } + + fn get_secret_for_reflect(&self) -> &::std::vec::Vec { + &self.secret + } + + fn mut_secret_for_reflect(&mut self) -> &mut ::std::vec::Vec { + &mut self.secret + } + + // string mime_type = 3; + + pub fn clear_mime_type(&mut self) { + self.mime_type.clear(); + } + + // Param is passed by value, moved + pub fn set_mime_type(&mut self, v: ::std::string::String) { + self.mime_type = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_mime_type(&mut self) -> &mut ::std::string::String { + &mut self.mime_type + } + + // Take field + pub fn take_mime_type(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.mime_type, ::std::string::String::new()) + } + + pub fn get_mime_type(&self) -> &str { + &self.mime_type + } + + fn get_mime_type_for_reflect(&self) -> &::std::string::String { + &self.mime_type + } + + fn mut_mime_type_for_reflect(&mut self) -> &mut ::std::string::String { + &mut self.mime_type + } +} + +impl ::protobuf::Message for SecretProto { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_enum()?; + self.version = tmp; + }, + 2 => { + ::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.secret)?; + }, + 3 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.mime_type)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if self.version != super::version::VersionProto::INITIAL_RELEASE { + my_size += ::protobuf::rt::enum_size(1, self.version); + } + if !self.secret.is_empty() { + my_size += ::protobuf::rt::bytes_size(2, &self.secret); + } + if !self.mime_type.is_empty() { + my_size += ::protobuf::rt::string_size(3, &self.mime_type); + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + if self.version != super::version::VersionProto::INITIAL_RELEASE { + os.write_enum(1, self.version.value())?; + } + if !self.secret.is_empty() { + os.write_bytes(2, &self.secret)?; + } + if !self.mime_type.is_empty() { + os.write_string(3, &self.mime_type)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &::std::any::Any { + self as &::std::any::Any + } + fn as_any_mut(&mut self) -> &mut ::std::any::Any { + self as &mut ::std::any::Any + } + fn into_any(self: Box) -> ::std::boxed::Box<::std::any::Any> { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + ::protobuf::MessageStatic::descriptor_static(None::) + } +} + +impl ::protobuf::MessageStatic for SecretProto { + fn new() -> SecretProto { + SecretProto::new() + } + + fn descriptor_static(_: ::std::option::Option) -> &'static ::protobuf::reflect::MessageDescriptor { + static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, + }; + unsafe { + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum>( + "version", + SecretProto::get_version_for_reflect, + SecretProto::mut_version_for_reflect, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( + "secret", + SecretProto::get_secret_for_reflect, + SecretProto::mut_secret_for_reflect, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "mime_type", + SecretProto::get_mime_type_for_reflect, + SecretProto::mut_mime_type_for_reflect, + )); + ::protobuf::reflect::MessageDescriptor::new::( + "SecretProto", + fields, + file_descriptor_proto() + ) + }) + } + } +} + +impl ::protobuf::Clear for SecretProto { + fn clear(&mut self) { + self.clear_version(); + self.clear_secret(); + self.clear_mime_type(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for SecretProto { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for SecretProto { + fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { + ::protobuf::reflect::ProtobufValueRef::Message(self) + } +} + +static file_descriptor_proto_data: &'static [u8] = b"\ + \n\x14wrapped/secret.proto\x12\x07wrapped\x1a\rversion.proto\"k\n\x0bSec\ + retProto\x12'\n\x07version\x18\x01\x20\x01(\x0e2\r.VersionProtoR\x07vers\ + ion\x12\x16\n\x06secret\x18\x02\x20\x01(\x0cR\x06secret\x12\x1b\n\tmime_\ + type\x18\x03\x20\x01(\tR\x08mimeTypeJ\x91\x02\n\x06\x12\x04\0\0\n\x01\n\ + \x08\n\x01\x0c\x12\x03\0\0\x12\n\x08\n\x01\x02\x12\x03\x02\x08\x0f\n\t\n\ + \x02\x03\0\x12\x03\x04\x07\x16\n\n\n\x02\x04\0\x12\x04\x06\0\n\x01\n\n\n\ + \x03\x04\0\x01\x12\x03\x06\x08\x13\n\x0b\n\x04\x04\0\x02\0\x12\x03\x07\ + \x08!\n\r\n\x05\x04\0\x02\0\x04\x12\x04\x07\x08\x06\x15\n\x0c\n\x05\x04\ + \0\x02\0\x06\x12\x03\x07\x08\x14\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x07\ + \x15\x1c\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x07\x1f\x20\n\x0b\n\x04\x04\ + \0\x02\x01\x12\x03\x08\x08\x19\n\r\n\x05\x04\0\x02\x01\x04\x12\x04\x08\ + \x08\x07!\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x08\x08\r\n\x0c\n\x05\ + \x04\0\x02\x01\x01\x12\x03\x08\x0e\x14\n\x0c\n\x05\x04\0\x02\x01\x03\x12\ + \x03\x08\x17\x18\n\x0b\n\x04\x04\0\x02\x02\x12\x03\t\x08\x1d\n\r\n\x05\ + \x04\0\x02\x02\x04\x12\x04\t\x08\x08\x19\n\x0c\n\x05\x04\0\x02\x02\x05\ + \x12\x03\t\x08\x0e\n\x0c\n\x05\x04\0\x02\x02\x01\x12\x03\t\x0f\x18\n\x0c\ + \n\x05\x04\0\x02\x02\x03\x12\x03\t\x1b\x1cb\x06proto3\ +"; + +static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::descriptor::FileDescriptorProto, +}; + +fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { + ::protobuf::parse_from_bytes(file_descriptor_proto_data).unwrap() +} + +pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { + unsafe { + file_descriptor_proto_lazy.get(|| { + parse_descriptor_proto() + }) + } +} diff --git a/src/proto/wrapped/share.rs b/src/proto/wrapped/share.rs new file mode 100644 index 0000000..3bbdbb6 --- /dev/null +++ b/src/proto/wrapped/share.rs @@ -0,0 +1,333 @@ +// This file is generated. Do not edit +// @generated + +// https://github.com/Manishearth/rust-clippy/issues/702 +#![allow(unknown_lints)] +#![allow(clippy)] + +#![cfg_attr(rustfmt, rustfmt_skip)] + +#![allow(box_pointers)] +#![allow(dead_code)] +#![allow(missing_docs)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(trivial_casts)] +#![allow(unsafe_code)] +#![allow(unused_imports)] +#![allow(unused_results)] + +use protobuf::Message as Message_imported_for_functions; +use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions; + +#[derive(PartialEq,Clone,Default)] +pub struct ShareProto { + // message fields + pub shamir_data: ::std::vec::Vec, + pub signature: ::protobuf::RepeatedField<::std::vec::Vec>, + pub proof: ::std::vec::Vec, + // special fields + unknown_fields: ::protobuf::UnknownFields, + cached_size: ::protobuf::CachedSize, +} + +// see codegen.rs for the explanation why impl Sync explicitly +unsafe impl ::std::marker::Sync for ShareProto {} + +impl ShareProto { + pub fn new() -> ShareProto { + ::std::default::Default::default() + } + + pub fn default_instance() -> &'static ShareProto { + static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ShareProto, + }; + unsafe { + instance.get(ShareProto::new) + } + } + + // bytes shamir_data = 1; + + pub fn clear_shamir_data(&mut self) { + self.shamir_data.clear(); + } + + // Param is passed by value, moved + pub fn set_shamir_data(&mut self, v: ::std::vec::Vec) { + self.shamir_data = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_shamir_data(&mut self) -> &mut ::std::vec::Vec { + &mut self.shamir_data + } + + // Take field + pub fn take_shamir_data(&mut self) -> ::std::vec::Vec { + ::std::mem::replace(&mut self.shamir_data, ::std::vec::Vec::new()) + } + + pub fn get_shamir_data(&self) -> &[u8] { + &self.shamir_data + } + + fn get_shamir_data_for_reflect(&self) -> &::std::vec::Vec { + &self.shamir_data + } + + fn mut_shamir_data_for_reflect(&mut self) -> &mut ::std::vec::Vec { + &mut self.shamir_data + } + + // repeated bytes signature = 2; + + pub fn clear_signature(&mut self) { + self.signature.clear(); + } + + // Param is passed by value, moved + pub fn set_signature(&mut self, v: ::protobuf::RepeatedField<::std::vec::Vec>) { + self.signature = v; + } + + // Mutable pointer to the field. + pub fn mut_signature(&mut self) -> &mut ::protobuf::RepeatedField<::std::vec::Vec> { + &mut self.signature + } + + // Take field + pub fn take_signature(&mut self) -> ::protobuf::RepeatedField<::std::vec::Vec> { + ::std::mem::replace(&mut self.signature, ::protobuf::RepeatedField::new()) + } + + pub fn get_signature(&self) -> &[::std::vec::Vec] { + &self.signature + } + + fn get_signature_for_reflect(&self) -> &::protobuf::RepeatedField<::std::vec::Vec> { + &self.signature + } + + fn mut_signature_for_reflect(&mut self) -> &mut ::protobuf::RepeatedField<::std::vec::Vec> { + &mut self.signature + } + + // bytes proof = 3; + + pub fn clear_proof(&mut self) { + self.proof.clear(); + } + + // Param is passed by value, moved + pub fn set_proof(&mut self, v: ::std::vec::Vec) { + self.proof = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_proof(&mut self) -> &mut ::std::vec::Vec { + &mut self.proof + } + + // Take field + pub fn take_proof(&mut self) -> ::std::vec::Vec { + ::std::mem::replace(&mut self.proof, ::std::vec::Vec::new()) + } + + pub fn get_proof(&self) -> &[u8] { + &self.proof + } + + fn get_proof_for_reflect(&self) -> &::std::vec::Vec { + &self.proof + } + + fn mut_proof_for_reflect(&mut self) -> &mut ::std::vec::Vec { + &mut self.proof + } +} + +impl ::protobuf::Message for ShareProto { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.shamir_data)?; + }, + 2 => { + ::protobuf::rt::read_repeated_bytes_into(wire_type, is, &mut self.signature)?; + }, + 3 => { + ::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.proof)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if !self.shamir_data.is_empty() { + my_size += ::protobuf::rt::bytes_size(1, &self.shamir_data); + } + for value in &self.signature { + my_size += ::protobuf::rt::bytes_size(2, &value); + }; + if !self.proof.is_empty() { + my_size += ::protobuf::rt::bytes_size(3, &self.proof); + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + if !self.shamir_data.is_empty() { + os.write_bytes(1, &self.shamir_data)?; + } + for v in &self.signature { + os.write_bytes(2, &v)?; + }; + if !self.proof.is_empty() { + os.write_bytes(3, &self.proof)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &::std::any::Any { + self as &::std::any::Any + } + fn as_any_mut(&mut self) -> &mut ::std::any::Any { + self as &mut ::std::any::Any + } + fn into_any(self: Box) -> ::std::boxed::Box<::std::any::Any> { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + ::protobuf::MessageStatic::descriptor_static(None::) + } +} + +impl ::protobuf::MessageStatic for ShareProto { + fn new() -> ShareProto { + ShareProto::new() + } + + fn descriptor_static(_: ::std::option::Option) -> &'static ::protobuf::reflect::MessageDescriptor { + static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, + }; + unsafe { + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( + "shamir_data", + ShareProto::get_shamir_data_for_reflect, + ShareProto::mut_shamir_data_for_reflect, + )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( + "signature", + ShareProto::get_signature_for_reflect, + ShareProto::mut_signature_for_reflect, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( + "proof", + ShareProto::get_proof_for_reflect, + ShareProto::mut_proof_for_reflect, + )); + ::protobuf::reflect::MessageDescriptor::new::( + "ShareProto", + fields, + file_descriptor_proto() + ) + }) + } + } +} + +impl ::protobuf::Clear for ShareProto { + fn clear(&mut self) { + self.clear_shamir_data(); + self.clear_signature(); + self.clear_proof(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for ShareProto { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for ShareProto { + fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { + ::protobuf::reflect::ProtobufValueRef::Message(self) + } +} + +static file_descriptor_proto_data: &'static [u8] = b"\ + \n\x13wrapped/share.proto\x12\x07wrapped\"a\n\nShareProto\x12\x1f\n\x0bs\ + hamir_data\x18\x01\x20\x01(\x0cR\nshamirData\x12\x1c\n\tsignature\x18\ + \x02\x20\x03(\x0cR\tsignature\x12\x14\n\x05proof\x18\x03\x20\x01(\x0cR\ + \x05proofJ\x85\x02\n\x06\x12\x04\0\0\x08\x01\n\x08\n\x01\x0c\x12\x03\0\0\ + \x12\n\x08\n\x01\x02\x12\x03\x02\x08\x0f\n\n\n\x02\x04\0\x12\x04\x04\0\ + \x08\x01\n\n\n\x03\x04\0\x01\x12\x03\x04\x08\x12\n\x0b\n\x04\x04\0\x02\0\ + \x12\x03\x05\x08\x1e\n\r\n\x05\x04\0\x02\0\x04\x12\x04\x05\x08\x04\x14\n\ + \x0c\n\x05\x04\0\x02\0\x05\x12\x03\x05\x08\r\n\x0c\n\x05\x04\0\x02\0\x01\ + \x12\x03\x05\x0e\x19\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x05\x1c\x1d\n\ + \x0b\n\x04\x04\0\x02\x01\x12\x03\x06\x08%\n\x0c\n\x05\x04\0\x02\x01\x04\ + \x12\x03\x06\x08\x10\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x06\x11\x16\n\ + \x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x06\x17\x20\n\x0c\n\x05\x04\0\x02\ + \x01\x03\x12\x03\x06#$\n\x0b\n\x04\x04\0\x02\x02\x12\x03\x07\x08\x18\n\r\ + \n\x05\x04\0\x02\x02\x04\x12\x04\x07\x08\x06%\n\x0c\n\x05\x04\0\x02\x02\ + \x05\x12\x03\x07\x08\r\n\x0c\n\x05\x04\0\x02\x02\x01\x12\x03\x07\x0e\x13\ + \n\x0c\n\x05\x04\0\x02\x02\x03\x12\x03\x07\x16\x17b\x06proto3\ +"; + +static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::descriptor::FileDescriptorProto, +}; + +fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { + ::protobuf::parse_from_bytes(file_descriptor_proto_data).unwrap() +} + +pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { + unsafe { + file_descriptor_proto_lazy.get(|| { + parse_descriptor_proto() + }) + } +} diff --git a/src/secret.rs b/src/secret.rs deleted file mode 100644 index 53aa6f9..0000000 --- a/src/secret.rs +++ /dev/null @@ -1,391 +0,0 @@ -// This file is generated. Do not edit -// @generated - -// https://github.com/Manishearth/rust-clippy/issues/702 -#![allow(unknown_lints)] -#![allow(clippy)] - -#![cfg_attr(rustfmt, rustfmt_skip)] - -#![allow(box_pointers)] -#![allow(dead_code)] -#![allow(non_camel_case_types)] -#![allow(non_snake_case)] -#![allow(non_upper_case_globals)] -#![allow(trivial_casts)] -#![allow(unsafe_code)] -#![allow(unused_imports)] -#![allow(unused_results)] - -use protobuf::Message as Message_imported_for_functions; -use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions; - -#[derive(Clone,Default)] -pub struct RustySecret { - // message fields - version: ::std::option::Option, - secret: ::protobuf::SingularField<::std::vec::Vec>, - mime_type: ::protobuf::SingularField<::std::string::String>, - // special fields - unknown_fields: ::protobuf::UnknownFields, - cached_size: ::std::cell::Cell, -} - -// see codegen.rs for the explanation why impl Sync explicitly -unsafe impl ::std::marker::Sync for RustySecret {} - -impl RustySecret { - pub fn new() -> RustySecret { - ::std::default::Default::default() - } - - pub fn default_instance() -> &'static RustySecret { - static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const RustySecret, - }; - unsafe { - instance.get(|| { - RustySecret { - version: ::std::option::Option::None, - secret: ::protobuf::SingularField::none(), - mime_type: ::protobuf::SingularField::none(), - unknown_fields: ::protobuf::UnknownFields::new(), - cached_size: ::std::cell::Cell::new(0), - } - }) - } - } - - // optional .RustySecretsVersions version = 1; - - pub fn clear_version(&mut self) { - self.version = ::std::option::Option::None; - } - - pub fn has_version(&self) -> bool { - self.version.is_some() - } - - // Param is passed by value, moved - pub fn set_version(&mut self, v: RustySecretsVersions) { - self.version = ::std::option::Option::Some(v); - } - - pub fn get_version(&self) -> RustySecretsVersions { - self.version.unwrap_or(RustySecretsVersions::INITIAL_RELEASE) - } - - // optional bytes secret = 2; - - pub fn clear_secret(&mut self) { - self.secret.clear(); - } - - pub fn has_secret(&self) -> bool { - self.secret.is_some() - } - - // Param is passed by value, moved - pub fn set_secret(&mut self, v: ::std::vec::Vec) { - self.secret = ::protobuf::SingularField::some(v); - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_secret(&mut self) -> &mut ::std::vec::Vec { - if self.secret.is_none() { - self.secret.set_default(); - }; - self.secret.as_mut().unwrap() - } - - // Take field - pub fn take_secret(&mut self) -> ::std::vec::Vec { - self.secret.take().unwrap_or_else(|| ::std::vec::Vec::new()) - } - - pub fn get_secret(&self) -> &[u8] { - match self.secret.as_ref() { - Some(v) => &v, - None => &[], - } - } - - // optional string mime_type = 3; - - pub fn clear_mime_type(&mut self) { - self.mime_type.clear(); - } - - pub fn has_mime_type(&self) -> bool { - self.mime_type.is_some() - } - - // Param is passed by value, moved - pub fn set_mime_type(&mut self, v: ::std::string::String) { - self.mime_type = ::protobuf::SingularField::some(v); - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_mime_type(&mut self) -> &mut ::std::string::String { - if self.mime_type.is_none() { - self.mime_type.set_default(); - }; - self.mime_type.as_mut().unwrap() - } - - // Take field - pub fn take_mime_type(&mut self) -> ::std::string::String { - self.mime_type.take().unwrap_or_else(|| ::std::string::String::new()) - } - - pub fn get_mime_type(&self) -> &str { - match self.mime_type.as_ref() { - Some(v) => &v, - None => "", - } - } -} - -impl ::protobuf::Message for RustySecret { - fn is_initialized(&self) -> bool { - true - } - - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { - while !try!(is.eof()) { - let (field_number, wire_type) = try!(is.read_tag_unpack()); - match field_number { - 1 => { - if wire_type != ::protobuf::wire_format::WireTypeVarint { - return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - }; - let tmp = try!(is.read_enum()); - self.version = ::std::option::Option::Some(tmp); - }, - 2 => { - try!(::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.secret)); - }, - 3 => { - try!(::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.mime_type)); - }, - _ => { - try!(::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())); - }, - }; - } - ::std::result::Result::Ok(()) - } - - // Compute sizes of nested messages - #[allow(unused_variables)] - fn compute_size(&self) -> u32 { - let mut my_size = 0; - for value in &self.version { - my_size += ::protobuf::rt::enum_size(1, *value); - }; - for value in &self.secret { - my_size += ::protobuf::rt::bytes_size(2, &value); - }; - for value in &self.mime_type { - my_size += ::protobuf::rt::string_size(3, &value); - }; - my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); - self.cached_size.set(my_size); - my_size - } - - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { - if let Some(v) = self.version { - try!(os.write_enum(1, v.value())); - }; - if let Some(v) = self.secret.as_ref() { - try!(os.write_bytes(2, &v)); - }; - if let Some(v) = self.mime_type.as_ref() { - try!(os.write_string(3, &v)); - }; - try!(os.write_unknown_fields(self.get_unknown_fields())); - ::std::result::Result::Ok(()) - } - - fn get_cached_size(&self) -> u32 { - self.cached_size.get() - } - - fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { - &self.unknown_fields - } - - fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { - &mut self.unknown_fields - } - - fn type_id(&self) -> ::std::any::TypeId { - ::std::any::TypeId::of::() - } - - fn as_any(&self) -> &::std::any::Any { - self as &::std::any::Any - } - - fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { - ::protobuf::MessageStatic::descriptor_static(None::) - } -} - -impl ::protobuf::MessageStatic for RustySecret { - fn new() -> RustySecret { - RustySecret::new() - } - - fn descriptor_static(_: ::std::option::Option) -> &'static ::protobuf::reflect::MessageDescriptor { - static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, - }; - unsafe { - descriptor.get(|| { - let mut fields = ::std::vec::Vec::new(); - fields.push(::protobuf::reflect::accessor::make_singular_enum_accessor( - "version", - RustySecret::has_version, - RustySecret::get_version, - )); - fields.push(::protobuf::reflect::accessor::make_singular_bytes_accessor( - "secret", - RustySecret::has_secret, - RustySecret::get_secret, - )); - fields.push(::protobuf::reflect::accessor::make_singular_string_accessor( - "mime_type", - RustySecret::has_mime_type, - RustySecret::get_mime_type, - )); - ::protobuf::reflect::MessageDescriptor::new::( - "RustySecret", - fields, - file_descriptor_proto() - ) - }) - } - } -} - -impl ::protobuf::Clear for RustySecret { - fn clear(&mut self) { - self.clear_version(); - self.clear_secret(); - self.clear_mime_type(); - self.unknown_fields.clear(); - } -} - -impl ::std::cmp::PartialEq for RustySecret { - fn eq(&self, other: &RustySecret) -> bool { - self.version == other.version && - self.secret == other.secret && - self.mime_type == other.mime_type && - self.unknown_fields == other.unknown_fields - } -} - -impl ::std::fmt::Debug for RustySecret { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - ::protobuf::text_format::fmt(self, f) - } -} - -#[derive(Clone,PartialEq,Eq,Debug,Hash)] -pub enum RustySecretsVersions { - INITIAL_RELEASE = 0, -} - -impl ::protobuf::ProtobufEnum for RustySecretsVersions { - fn value(&self) -> i32 { - *self as i32 - } - - fn from_i32(value: i32) -> ::std::option::Option { - match value { - 0 => ::std::option::Option::Some(RustySecretsVersions::INITIAL_RELEASE), - _ => ::std::option::Option::None - } - } - - fn values() -> &'static [Self] { - static values: &'static [RustySecretsVersions] = &[ - RustySecretsVersions::INITIAL_RELEASE, - ]; - values - } - - fn enum_descriptor_static(_: Option) -> &'static ::protobuf::reflect::EnumDescriptor { - static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::EnumDescriptor> = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ::protobuf::reflect::EnumDescriptor, - }; - unsafe { - descriptor.get(|| { - ::protobuf::reflect::EnumDescriptor::new("RustySecretsVersions", file_descriptor_proto()) - }) - } - } -} - -impl ::std::marker::Copy for RustySecretsVersions { -} - -static file_descriptor_proto_data: &'static [u8] = &[ - 0x0a, 0x0c, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x73, - 0x0a, 0x0b, 0x52, 0x75, 0x73, 0x74, 0x79, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x2f, 0x0a, - 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, - 0x2e, 0x52, 0x75, 0x73, 0x74, 0x79, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x56, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, - 0x0a, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, - 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x69, 0x6d, 0x65, 0x5f, 0x74, - 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x69, 0x6d, 0x65, 0x54, - 0x79, 0x70, 0x65, 0x2a, 0x2b, 0x0a, 0x14, 0x52, 0x75, 0x73, 0x74, 0x79, 0x53, 0x65, 0x63, 0x72, - 0x65, 0x74, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x13, 0x0a, 0x0f, 0x49, - 0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c, 0x5f, 0x52, 0x45, 0x4c, 0x45, 0x41, 0x53, 0x45, 0x10, 0x00, - 0x4a, 0xbd, 0x02, 0x0a, 0x06, 0x12, 0x04, 0x00, 0x00, 0x0a, 0x01, 0x0a, 0x08, 0x0a, 0x01, 0x0c, - 0x12, 0x03, 0x00, 0x00, 0x12, 0x0a, 0x0a, 0x0a, 0x02, 0x05, 0x00, 0x12, 0x04, 0x02, 0x00, 0x04, - 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x05, 0x00, 0x01, 0x12, 0x03, 0x02, 0x05, 0x19, 0x0a, 0x0b, 0x0a, - 0x04, 0x05, 0x00, 0x02, 0x00, 0x12, 0x03, 0x03, 0x08, 0x1c, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, - 0x02, 0x00, 0x01, 0x12, 0x03, 0x03, 0x08, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x05, 0x00, 0x02, 0x00, - 0x02, 0x12, 0x03, 0x03, 0x1a, 0x1b, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x06, 0x00, - 0x0a, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x06, 0x08, 0x13, 0x0a, 0x0b, - 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x07, 0x08, 0x29, 0x0a, 0x0d, 0x0a, 0x05, 0x04, - 0x00, 0x02, 0x00, 0x04, 0x12, 0x04, 0x07, 0x08, 0x06, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, - 0x02, 0x00, 0x06, 0x12, 0x03, 0x07, 0x08, 0x1c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, - 0x01, 0x12, 0x03, 0x07, 0x1d, 0x24, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, - 0x03, 0x07, 0x27, 0x28, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x08, 0x08, - 0x19, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x04, 0x12, 0x04, 0x08, 0x08, 0x07, 0x29, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x05, 0x12, 0x03, 0x08, 0x08, 0x0d, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x08, 0x0e, 0x14, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, 0x08, 0x17, 0x18, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, - 0x02, 0x02, 0x12, 0x03, 0x09, 0x08, 0x1d, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x04, - 0x12, 0x04, 0x09, 0x08, 0x08, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x05, 0x12, - 0x03, 0x09, 0x08, 0x0e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x09, - 0x0f, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x03, 0x12, 0x03, 0x09, 0x1b, 0x1c, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -]; - -static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ::protobuf::descriptor::FileDescriptorProto, -}; - -fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { - ::protobuf::parse_from_bytes(file_descriptor_proto_data).unwrap() -} - -pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { - unsafe { - file_descriptor_proto_lazy.get(|| { - parse_descriptor_proto() - }) - } -} diff --git a/src/share/mod.rs b/src/share/mod.rs new file mode 100644 index 0000000..beb1c5c --- /dev/null +++ b/src/share/mod.rs @@ -0,0 +1,40 @@ +//! Define the traits used to distinguish the various +//! kind of shares internally used by the library. +//! These traits are currently not exposed, but this might +//! change in the future. + +use errors::*; + +pub(crate) mod validation; + +/// All types of share should implement this trait. +pub(crate) trait IsShare: Sized { + /// Returns the identifier of the share. + /// Varies between 1 and n where n is the total number of generated shares. + fn get_id(&self) -> u8; + + /// Returns the share data itself + fn get_data(&self) -> &[u8]; + + /// Returns the number of shares necessary to recover the secret, aka the threshold + fn get_threshold(&self) -> u8; + + /// Returns the total number of shares that have been dealt + fn get_shares_count(&self) -> Option; +} + +/// This trait must be implemented by shares' types wich can be signed. +pub(crate) trait IsSignedShare: IsShare { + /// The type of shares' sigature. + type Signature; + + /// Returns whether this share is signed or not. + fn is_signed(&self) -> bool; + + /// Return the signature itself. + fn get_signature(&self) -> &Self::Signature; + + /// Verify the signatures of the given batch of shares. + /// Returns `Ok(())` if validation succeeds, and an `Err` otherwise. + fn verify_signatures(shares: &[Self]) -> Result<()>; +} diff --git a/src/share/validation.rs b/src/share/validation.rs new file mode 100644 index 0000000..f8f94ad --- /dev/null +++ b/src/share/validation.rs @@ -0,0 +1,113 @@ +use std::collections::{HashMap, HashSet}; + +use errors::*; +use share::{IsShare, IsSignedShare}; + +// The order of validation that we think makes the most sense is the following: +// 1) Validate shares individually +// 2) Validate duplicate shares share num && data +// 2) Validate group consistency +// 3) Validate other properties, in no specific order + +/// TODO: Doc +pub(crate) fn validate_signed_shares( + shares: Vec, + verify_signatures: bool, +) -> Result<(u8, Vec)> { + let (threshold, shares) = validate_shares(shares)?; + + if verify_signatures { + S::verify_signatures(&shares)?; + } + + Ok((threshold, shares)) +} + +/// TODO: Doc +pub(crate) fn validate_shares(shares: Vec) -> Result<(u8, Vec)> { + if shares.is_empty() { + bail!(ErrorKind::EmptyShares); + } + + let shares_count = shares.len(); + let mut result: Vec = Vec::with_capacity(shares_count); + + let mut k_compatibility_sets = HashMap::new(); + + for share in shares { + let (id, threshold) = (share.get_id(), share.get_threshold()); + + if id > MAX_SHARES { + bail!(ErrorKind::ShareIdentifierTooBig(id, MAX_SHARES)) + } + + if id < 1 { + bail!(ErrorKind::ShareParsingInvalidShareId(id)) + } + + k_compatibility_sets + .entry(threshold) + .or_insert_with(HashSet::new); + let k_set = k_compatibility_sets.get_mut(&threshold).unwrap(); + k_set.insert(id); + + if result.iter().any(|s| s.get_id() == id) { + bail!(ErrorKind::DuplicateShareId(id)); + } + + if share.get_data().is_empty() { + bail!(ErrorKind::ShareParsingErrorEmptyShare(id)) + } + + if result.iter().any(|s| s.get_data() == share.get_data()) && share.get_threshold() != 1 { + // When threshold = 1, shares data can be the same + bail!(ErrorKind::DuplicateShareData(id)); + } + + result.push(share); + } + + // Validate threshold + let k_sets = k_compatibility_sets.keys().count(); + + match k_sets { + 0 => bail!(ErrorKind::EmptyShares), + 1 => {} // All shares have the same roothash. + _ => { + bail! { + ErrorKind::IncompatibleSets( + k_compatibility_sets + .values() + .map(|x| x.to_owned()) + .collect(), + ) + } + } + } + + // It is safe to unwrap because k_sets == 1 + let threshold = k_compatibility_sets.keys().last().unwrap().to_owned(); + + if shares_count < threshold as usize { + bail!(ErrorKind::MissingShares(threshold as usize, shares_count)); + } + + Ok((threshold, result)) +} + +pub(crate) fn validate_share_count(threshold: u8, shares_count: u8) -> Result<(u8, u8)> { + if threshold < MIN_SHARES { + bail!(ErrorKind::ThresholdTooSmall(threshold)); + } + if shares_count > MAX_SHARES { + bail!(ErrorKind::InvalidShareCountMax(shares_count, MAX_SHARES)); + } + if shares_count < MIN_SHARES { + bail!(ErrorKind::InvalidShareCountMin(shares_count, MIN_SHARES)); + } + if threshold > shares_count { + bail!(ErrorKind::ThresholdTooBig(threshold, shares_count)); + } + + Ok((threshold, shares_count)) +} diff --git a/src/share_data.rs b/src/share_data.rs deleted file mode 100644 index 818911f..0000000 --- a/src/share_data.rs +++ /dev/null @@ -1,345 +0,0 @@ -// This file is generated. Do not edit -// @generated - -// https://github.com/Manishearth/rust-clippy/issues/702 -#![allow(unknown_lints)] -#![allow(clippy)] - -#![cfg_attr(rustfmt, rustfmt_skip)] - -#![allow(box_pointers)] -#![allow(dead_code)] -#![allow(non_camel_case_types)] -#![allow(non_snake_case)] -#![allow(non_upper_case_globals)] -#![allow(trivial_casts)] -#![allow(unsafe_code)] -#![allow(unused_imports)] -#![allow(unused_results)] - -use protobuf::Message as Message_imported_for_functions; -use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions; - -#[derive(Clone,Default)] -pub struct ShareData { - // message fields - shamir_data: ::protobuf::SingularField<::std::vec::Vec>, - signature: ::protobuf::RepeatedField<::std::vec::Vec>, - proof: ::protobuf::SingularField<::std::vec::Vec>, - // special fields - unknown_fields: ::protobuf::UnknownFields, - cached_size: ::std::cell::Cell, -} - -// see codegen.rs for the explanation why impl Sync explicitly -unsafe impl ::std::marker::Sync for ShareData {} - -impl ShareData { - pub fn new() -> ShareData { - ::std::default::Default::default() - } - - pub fn default_instance() -> &'static ShareData { - static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ShareData, - }; - unsafe { - instance.get(|| { - ShareData { - shamir_data: ::protobuf::SingularField::none(), - signature: ::protobuf::RepeatedField::new(), - proof: ::protobuf::SingularField::none(), - unknown_fields: ::protobuf::UnknownFields::new(), - cached_size: ::std::cell::Cell::new(0), - } - }) - } - } - - // optional bytes shamir_data = 1; - - pub fn clear_shamir_data(&mut self) { - self.shamir_data.clear(); - } - - pub fn has_shamir_data(&self) -> bool { - self.shamir_data.is_some() - } - - // Param is passed by value, moved - pub fn set_shamir_data(&mut self, v: ::std::vec::Vec) { - self.shamir_data = ::protobuf::SingularField::some(v); - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_shamir_data(&mut self) -> &mut ::std::vec::Vec { - if self.shamir_data.is_none() { - self.shamir_data.set_default(); - }; - self.shamir_data.as_mut().unwrap() - } - - // Take field - pub fn take_shamir_data(&mut self) -> ::std::vec::Vec { - self.shamir_data.take().unwrap_or_else(|| ::std::vec::Vec::new()) - } - - pub fn get_shamir_data(&self) -> &[u8] { - match self.shamir_data.as_ref() { - Some(v) => &v, - None => &[], - } - } - - // repeated bytes signature = 2; - - pub fn clear_signature(&mut self) { - self.signature.clear(); - } - - // Param is passed by value, moved - pub fn set_signature(&mut self, v: ::protobuf::RepeatedField<::std::vec::Vec>) { - self.signature = v; - } - - // Mutable pointer to the field. - pub fn mut_signature(&mut self) -> &mut ::protobuf::RepeatedField<::std::vec::Vec> { - &mut self.signature - } - - // Take field - pub fn take_signature(&mut self) -> ::protobuf::RepeatedField<::std::vec::Vec> { - ::std::mem::replace(&mut self.signature, ::protobuf::RepeatedField::new()) - } - - pub fn get_signature(&self) -> &[::std::vec::Vec] { - &self.signature - } - - // optional bytes proof = 3; - - pub fn clear_proof(&mut self) { - self.proof.clear(); - } - - pub fn has_proof(&self) -> bool { - self.proof.is_some() - } - - // Param is passed by value, moved - pub fn set_proof(&mut self, v: ::std::vec::Vec) { - self.proof = ::protobuf::SingularField::some(v); - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_proof(&mut self) -> &mut ::std::vec::Vec { - if self.proof.is_none() { - self.proof.set_default(); - }; - self.proof.as_mut().unwrap() - } - - // Take field - pub fn take_proof(&mut self) -> ::std::vec::Vec { - self.proof.take().unwrap_or_else(|| ::std::vec::Vec::new()) - } - - pub fn get_proof(&self) -> &[u8] { - match self.proof.as_ref() { - Some(v) => &v, - None => &[], - } - } -} - -impl ::protobuf::Message for ShareData { - fn is_initialized(&self) -> bool { - true - } - - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { - while !try!(is.eof()) { - let (field_number, wire_type) = try!(is.read_tag_unpack()); - match field_number { - 1 => { - try!(::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.shamir_data)); - }, - 2 => { - try!(::protobuf::rt::read_repeated_bytes_into(wire_type, is, &mut self.signature)); - }, - 3 => { - try!(::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.proof)); - }, - _ => { - try!(::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())); - }, - }; - } - ::std::result::Result::Ok(()) - } - - // Compute sizes of nested messages - #[allow(unused_variables)] - fn compute_size(&self) -> u32 { - let mut my_size = 0; - for value in &self.shamir_data { - my_size += ::protobuf::rt::bytes_size(1, &value); - }; - for value in &self.signature { - my_size += ::protobuf::rt::bytes_size(2, &value); - }; - for value in &self.proof { - my_size += ::protobuf::rt::bytes_size(3, &value); - }; - my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); - self.cached_size.set(my_size); - my_size - } - - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { - if let Some(v) = self.shamir_data.as_ref() { - try!(os.write_bytes(1, &v)); - }; - for v in &self.signature { - try!(os.write_bytes(2, &v)); - }; - if let Some(v) = self.proof.as_ref() { - try!(os.write_bytes(3, &v)); - }; - try!(os.write_unknown_fields(self.get_unknown_fields())); - ::std::result::Result::Ok(()) - } - - fn get_cached_size(&self) -> u32 { - self.cached_size.get() - } - - fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { - &self.unknown_fields - } - - fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { - &mut self.unknown_fields - } - - fn type_id(&self) -> ::std::any::TypeId { - ::std::any::TypeId::of::() - } - - fn as_any(&self) -> &::std::any::Any { - self as &::std::any::Any - } - - fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { - ::protobuf::MessageStatic::descriptor_static(None::) - } -} - -impl ::protobuf::MessageStatic for ShareData { - fn new() -> ShareData { - ShareData::new() - } - - fn descriptor_static(_: ::std::option::Option) -> &'static ::protobuf::reflect::MessageDescriptor { - static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, - }; - unsafe { - descriptor.get(|| { - let mut fields = ::std::vec::Vec::new(); - fields.push(::protobuf::reflect::accessor::make_singular_bytes_accessor( - "shamir_data", - ShareData::has_shamir_data, - ShareData::get_shamir_data, - )); - fields.push(::protobuf::reflect::accessor::make_repeated_bytes_accessor( - "signature", - ShareData::get_signature, - )); - fields.push(::protobuf::reflect::accessor::make_singular_bytes_accessor( - "proof", - ShareData::has_proof, - ShareData::get_proof, - )); - ::protobuf::reflect::MessageDescriptor::new::( - "ShareData", - fields, - file_descriptor_proto() - ) - }) - } - } -} - -impl ::protobuf::Clear for ShareData { - fn clear(&mut self) { - self.clear_shamir_data(); - self.clear_signature(); - self.clear_proof(); - self.unknown_fields.clear(); - } -} - -impl ::std::cmp::PartialEq for ShareData { - fn eq(&self, other: &ShareData) -> bool { - self.shamir_data == other.shamir_data && - self.signature == other.signature && - self.proof == other.proof && - self.unknown_fields == other.unknown_fields - } -} - -impl ::std::fmt::Debug for ShareData { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - ::protobuf::text_format::fmt(self, f) - } -} - -static file_descriptor_proto_data: &'static [u8] = &[ - 0x0a, 0x18, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x53, 0x68, 0x61, 0x72, 0x65, - 0x44, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x60, 0x0a, 0x09, 0x53, 0x68, - 0x61, 0x72, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x68, 0x61, 0x6d, 0x69, - 0x72, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x73, 0x68, - 0x61, 0x6d, 0x69, 0x72, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x4a, 0xfb, 0x01, 0x0a, - 0x06, 0x12, 0x04, 0x00, 0x00, 0x06, 0x01, 0x0a, 0x08, 0x0a, 0x01, 0x0c, 0x12, 0x03, 0x00, 0x00, - 0x12, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x02, 0x00, 0x06, 0x01, 0x0a, 0x0a, 0x0a, - 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x02, 0x08, 0x11, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, - 0x00, 0x12, 0x03, 0x03, 0x08, 0x1e, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x04, 0x12, - 0x04, 0x03, 0x08, 0x02, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x05, 0x12, 0x03, - 0x03, 0x08, 0x0d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x03, 0x0e, - 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x03, 0x1c, 0x1d, 0x0a, - 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x04, 0x08, 0x25, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x00, 0x02, 0x01, 0x04, 0x12, 0x03, 0x04, 0x08, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, - 0x02, 0x01, 0x05, 0x12, 0x03, 0x04, 0x11, 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, - 0x01, 0x12, 0x03, 0x04, 0x17, 0x20, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x03, 0x12, - 0x03, 0x04, 0x23, 0x24, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x02, 0x12, 0x03, 0x05, 0x08, - 0x18, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x04, 0x12, 0x04, 0x05, 0x08, 0x04, 0x25, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x05, 0x12, 0x03, 0x05, 0x08, 0x0d, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, 0x05, 0x0e, 0x13, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x00, 0x02, 0x02, 0x03, 0x12, 0x03, 0x05, 0x16, 0x17, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, -]; - -static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ::protobuf::descriptor::FileDescriptorProto, -}; - -fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { - ::protobuf::parse_from_bytes(file_descriptor_proto_data).unwrap() -} - -pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { - unsafe { - file_descriptor_proto_lazy.get(|| { - parse_descriptor_proto() - }) - } -} diff --git a/src/share_format.rs b/src/share_format.rs deleted file mode 100644 index e070f8b..0000000 --- a/src/share_format.rs +++ /dev/null @@ -1,87 +0,0 @@ -use custom_error::{RustyError, RustyErrorTypes}; -use custom_error::pie2error; -use digest; -use merkle_sigs::{MerklePublicKey, Proof, PublicKey}; -use protobuf; -use protobuf::{Message, RepeatedField}; -use serialize; -use serialize::base64::{self, FromBase64, ToBase64}; -use share_data::ShareData; -use std::error::Error; - -type ParsedShare = Result<(Vec, u8, u8, Option<(Vec>, Proof)>), RustyError>; - -fn base64_config() -> serialize::base64::Config { - base64::Config { pad: false, ..base64::STANDARD } -} - -pub fn share_string_from(share: Vec, threshold: u8, share_num: u8, - signature_pair: Option<(Vec>, Proof)>) - -> String { - let mut share_protobuf = ShareData::new(); - share_protobuf.set_shamir_data(share); - - if signature_pair.is_some() { - let (signature, proof) = signature_pair.unwrap(); - share_protobuf.set_signature(RepeatedField::from_vec(signature)); - share_protobuf.set_proof(proof.write_to_bytes().unwrap()); - } - - let b64_share = share_protobuf.write_to_bytes().unwrap().to_base64(base64_config()); - format!("{}-{}-{}", threshold, share_num, b64_share) -} - -pub fn share_from_string - (s: &str, - index: u8, - is_signed: bool) - -> ParsedShare { - let parts: Vec<_> = s.trim().split('-').collect(); - - if parts.len() != 3 { - return Err(RustyError::with_type(RustyErrorTypes::ShareParsingError(index, format!("Expected 3 parts separated by a minus sign. Found {}.", s)))); - } - let (k, n, p3) = { - let mut iter = parts.into_iter(); - let k = try!(iter.next().unwrap().parse::().map_err(pie2error)); - let n = try!(iter.next().unwrap().parse::().map_err(pie2error)); - let p3 = iter.next().unwrap(); - (k, n, p3) - }; - if k < 1 || n < 1 { - return Err(RustyError::with_type(RustyErrorTypes::ShareParsingError(index, format!("Found illegal parameters K: {} N: {}.", k, n)))); - } - - let raw_data = try!(p3.from_base64().map_err(|_| { - RustyError::with_type(RustyErrorTypes::ShareParsingError(index, "Base64 decoding of data block failed".to_owned())) - })); - - let protobuf_data = try!(protobuf::parse_from_bytes::(raw_data.as_slice()) - .map_err(|e| RustyError::with_type(RustyErrorTypes::ShareParsingError(index, format!("Protobuf decoding of data block failed with error: {} .", e.description()))))); - - let share = Vec::from(protobuf_data.get_shamir_data()); - - if is_signed { - let p_result = Proof::parse_from_bytes(protobuf_data.get_proof(), digest); - - let p_opt = p_result.unwrap(); - let p = p_opt.unwrap(); - - let proof = Proof { - algorithm: digest, - lemma: p.lemma, - root_hash: p.root_hash, - value: MerklePublicKey::new(PublicKey::from_vec(p.value, digest).unwrap()), - }; - - let signature = protobuf_data.get_signature(); - - Ok((share, k, n, Some((Vec::from(signature), proof)))) - } else { - Ok((share, k, n, None)) - } -} - -pub fn format_share_for_signing(k: u8, i: u8, data: &[u8]) -> Vec { - format!("{}-{}-{}", k, i, data.to_base64(base64_config())).into_bytes() -} diff --git a/src/sss.rs b/src/sss.rs deleted file mode 100644 index b6a8c5e..0000000 --- a/src/sss.rs +++ /dev/null @@ -1,128 +0,0 @@ -//! SSS provides Shamir's secret sharing with raw data. - -use custom_error::{RustyError, other_io_err}; -use digest; -use interpolation::{encode, lagrange_interpolate}; -use merkle_sigs::sign_data_vec; -use rand::{OsRng, Rng}; -use share_format::format_share_for_signing; -use share_format::share_string_from; -use std::io; -use std::iter::repeat; -use validation::process_and_validate_shares; - -fn new_vec(n: usize, x: T) -> Vec { - repeat(x).take(n).collect() -} - -/// Performs threshold k-out-of-n Shamir's secret sharing. -/// -/// # Examples -/// -/// ``` -/// use rusty_secrets::sss::generate_shares; -/// let secret = "These programs were never about terrorism: they’re about economic spying, -/// social control, and diplomatic manipulation. They’re about power.".to_string(); -/// -/// match generate_shares(7, 10, &secret.into_bytes(), true){ -/// Ok(shares) => { -/// // Do something with the shares -/// }, -/// Err(_) => {}// Deal with error} -/// } -/// ``` -pub fn generate_shares(k: u8, n: u8, secret: &[u8], sign_shares: bool) -> io::Result> { - if k > n { - return Err(other_io_err("Threshold K can not be larger than N", None, None, None)); - } - - let shares = try!(secret_share(secret, k, n)); - - let signatures = if sign_shares { - let shares_to_sign = shares.iter() - .enumerate() - .map(|(i, x)| format_share_for_signing(k, (i + 1) as u8, x)) - .collect::>(); - - let sign = sign_data_vec(&shares_to_sign, digest) - .unwrap() - .into_iter() - .map(Some) - .collect::>(); - - Some(sign) - } else { - None - }; - - let mut result = Vec::with_capacity(n as usize); - - for ((index, share), signature_pair) in - shares.into_iter() - .enumerate() - .zip(signatures.unwrap_or_else(|| vec![None; n as usize]).into_iter()) { - let share_string = share_string_from(share, k, (index + 1) as u8, signature_pair); - result.push(share_string); - } - - Ok(result) -} - -fn secret_share(src: &[u8], k: u8, n: u8) -> Result>, RustyError> { - let mut result = Vec::with_capacity(n as usize); - for _ in 0..(n as usize) { - result.push(new_vec(src.len(), 0u8)); - } - let mut col_in = new_vec(k as usize, 0u8); - let mut col_out = Vec::with_capacity(n as usize); - let mut osrng = try!(OsRng::new()); - for (c, &s) in src.iter().enumerate() { - col_in[0] = s; - osrng.fill_bytes(&mut col_in[1..]); - col_out.clear(); - try!(encode(&*col_in, n, &mut col_out)); - for (&y, share) in col_out.iter().zip(result.iter_mut()) { - share[c] = y; - } - } - Ok(result) -} - - -/// Recovers the secret from a k-out-of-n Shamir's secret sharing. -/// -/// At least `k` distinct shares need to be provided to recover the share. -/// -/// # Examples -/// -/// ``` -/// use rusty_secrets::sss::recover_secret; -/// let share1 = "2-1-Cha7s14Q/mSwWko0ittr+/Uf79RHQMIP".to_string(); -/// let share2 = "2-4-ChaydsUJDypD9ZWxwvIICh/cmZvzusOF".to_string(); -/// let shares = vec![share1, share2]; -/// -/// match recover_secret(shares, false) { -/// Ok(secret) => { -/// // Do something with the secret -/// }, -/// Err(e) => { -/// // Deal with the error -/// } -/// } -/// ``` -pub fn recover_secret(shares: Vec, verify_signatures: bool) -> Result, RustyError> { - let (k, shares) = try!(process_and_validate_shares(shares, verify_signatures)); - - let slen = shares[0].1.len(); - let mut col_in = Vec::with_capacity(k as usize); - let mut secret = Vec::with_capacity(slen); - for byteindex in 0..slen { - col_in.clear(); - for s in shares.iter().take(k as usize) { - col_in.push((s.0, s.1[byteindex])); - } - secret.push(lagrange_interpolate(&*col_in)); - } - - Ok(secret) -} diff --git a/src/sss/encode.rs b/src/sss/encode.rs new file mode 100644 index 0000000..204e08c --- /dev/null +++ b/src/sss/encode.rs @@ -0,0 +1,18 @@ +use gf256::Gf256; +use std::io; +use std::io::prelude::*; + +/// evaluates a polynomial at x=1, 2, 3, ... n (inclusive) +pub(crate) fn encode_secret_byte(src: &[u8], n: u8, w: &mut W) -> io::Result<()> { + for raw_x in 1..(u16::from(n) + 1) { + let x = Gf256::from_byte(raw_x as u8); + let mut fac = Gf256::one(); + let mut acc = Gf256::zero(); + for &coeff in src.iter() { + acc = acc + fac * Gf256::from_byte(coeff); + fac = fac * x; + } + w.write_all(&[acc.to_byte()])?; + } + Ok(()) +} diff --git a/src/sss/format.rs b/src/sss/format.rs new file mode 100644 index 0000000..0e7c3ea --- /dev/null +++ b/src/sss/format.rs @@ -0,0 +1,104 @@ +use errors::*; +use merkle_sigs::{MerklePublicKey, Proof, PublicKey}; +use protobuf::{self, Message, RepeatedField}; +use base64; +use sss::{Share, HASH_ALGO}; +use proto::wrapped::ShareProto; +use std::error::Error; + +const BASE64_CONFIG: base64::Config = base64::STANDARD_NO_PAD; + +pub(crate) fn share_to_string( + share: Vec, + threshold: u8, + share_num: u8, + signature_pair: Option<(Vec>, Proof)>, +) -> String { + let mut share_protobuf = ShareProto::new(); + share_protobuf.set_shamir_data(share); + + if signature_pair.is_some() { + let (signature, proof) = signature_pair.unwrap(); + share_protobuf.set_signature(RepeatedField::from_vec(signature)); + share_protobuf.set_proof(proof.write_to_bytes().unwrap()); + } + + let proto_buf = share_protobuf.write_to_bytes().unwrap(); + let b64_share = base64::encode_config(&proto_buf, BASE64_CONFIG); + format!("{}-{}-{}", threshold, share_num, b64_share) +} + +pub(crate) fn share_from_string(s: &str, is_signed: bool) -> Result { + let parts: Vec<_> = s.trim().split('-').collect(); + + if parts.len() != SSS_SHARE_PARTS_COUNT { + bail! { + ErrorKind::ShareParsingError( + format!( + "Expected 3 parts separated by a minus sign. Found {}.", + s + ), + ) + }; + } + let (k, i, p3) = { + let mut iter = parts.into_iter(); + let k = iter.next().unwrap().parse::()?; + let i = iter.next().unwrap().parse::()?; + let p3 = iter.next().unwrap(); + (k, i, p3) + }; + + if k < 1 || i < 1 { + bail! { + ErrorKind::ShareParsingError( + format!("Found illegal share info: threshold = {}, identifier = {}.", k, i), + ) + } + } + + let raw_data = base64::decode_config(p3, BASE64_CONFIG).chain_err(|| { + ErrorKind::ShareParsingError("Base64 decoding of data block failed".to_owned()) + })?; + + let protobuf_data = + protobuf::parse_from_bytes::(raw_data.as_slice()).map_err(|e| { + ErrorKind::ShareParsingError(format!( + "Protobuf decoding of data block failed with error: {} .", + e.description() + )) + })?; + + let data = Vec::from(protobuf_data.get_shamir_data()); + + let signature_pair = if is_signed { + let p_result = Proof::parse_from_bytes(protobuf_data.get_proof(), HASH_ALGO); + + let p_opt = p_result.unwrap(); + let p = p_opt.unwrap(); + + let proof = Proof { + algorithm: HASH_ALGO, + lemma: p.lemma, + root_hash: p.root_hash, + value: MerklePublicKey::new(PublicKey::from_vec(p.value, HASH_ALGO).unwrap()), + }; + + let signature = protobuf_data.get_signature(); + Some((Vec::from(signature), proof).into()) + } else { + None + }; + + Ok(Share { + id: i, + data, + threshold: k, + signature_pair, + }) +} + +pub(crate) fn format_share_for_signing(k: u8, i: u8, data: &[u8]) -> Vec { + let b64_data = base64::encode_config(data, BASE64_CONFIG); + format!("{}-{}-{}", k, i, b64_data).into_bytes() +} diff --git a/src/sss/mod.rs b/src/sss/mod.rs new file mode 100644 index 0000000..7709d1b --- /dev/null +++ b/src/sss/mod.rs @@ -0,0 +1,69 @@ +//! SSS provides Shamir's secret sharing with raw data. + +use errors::*; + +mod share; +pub(crate) use self::share::*; + +mod format; +// pub use self::format::*; + +mod scheme; +pub(crate) use self::scheme::*; + +mod encode; + +use ring::digest::{Algorithm, SHA512}; +static HASH_ALGO: &'static Algorithm = &SHA512; + +/// Performs threshold k-out-of-n Shamir's secret sharing. +/// +/// # Examples +/// +/// ``` +/// use rusty_secrets::sss::split_secret; +/// +/// let secret = "These programs were never about terrorism: they’re about economic spying, \ +/// social control, and diplomatic manipulation. They’re about power."; +/// +/// match split_secret(7, 10, &secret.as_bytes(), true) { +/// Ok(shares) => { +/// // Do something with the shares +/// }, +/// Err(_) => { +/// // Deal with error +/// } +/// } +/// ``` +pub fn split_secret(k: u8, n: u8, secret: &[u8], sign_shares: bool) -> Result> { + SSS::default() + .split_secret(k, n, secret, sign_shares) + .map(|shares| shares.into_iter().map(Share::into_string).collect()) +} + +/// Recovers the secret from a k-out-of-n Shamir's secret sharing scheme. +/// +/// At least `k` distinct shares need to be provided to recover the secret. +/// +/// # Examples +/// +/// ``` +/// use rusty_secrets::sss::recover_secret; +/// +/// let share1 = "2-1-Cha7s14Q/mSwWko0ittr+/Uf79RHQMIP".to_string(); +/// let share2 = "2-4-ChaydsUJDypD9ZWxwvIICh/cmZvzusOF".to_string(); +/// let shares = vec![share1, share2]; +/// +/// match recover_secret(&shares, false) { +/// Ok(secret) => { +/// // Do something with the secret +/// }, +/// Err(e) => { +/// // Deal with the error +/// } +/// } +/// ``` +pub fn recover_secret(shares: &[String], verify_signatures: bool) -> Result> { + let shares = Share::parse_all(shares, verify_signatures)?; + SSS::recover_secret(shares, verify_signatures) +} diff --git a/src/sss/scheme.rs b/src/sss/scheme.rs new file mode 100644 index 0000000..542fe3b --- /dev/null +++ b/src/sss/scheme.rs @@ -0,0 +1,109 @@ +//! SSS provides Shamir's secret sharing with raw data. + +use rand::{OsRng, Rng}; +use merkle_sigs::sign_data_vec; + +use errors::*; +use sss::{Share, HASH_ALGO}; +use sss::format::format_share_for_signing; +use share::validation::{validate_share_count, validate_signed_shares}; +use lagrange::interpolate_at; + +use super::encode::encode_secret_byte; + +/// SSS provides Shamir's secret sharing with raw data. +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] +pub(crate) struct SSS; + +impl SSS { + /// Performs threshold k-out-of-n Shamir's secret sharing. + pub fn split_secret( + &self, + threshold: u8, + shares_count: u8, + secret: &[u8], + sign_shares: bool, + ) -> Result> { + let (threshold, shares_count) = validate_share_count(threshold, shares_count)?; + let shares = Self::secret_share(secret, threshold, shares_count)?; + + let signatures = if sign_shares { + let shares_to_sign = shares + .iter() + .enumerate() + .map(|(i, x)| format_share_for_signing(threshold, (i + 1) as u8, x)) + .collect::>(); + + let sign = sign_data_vec(&shares_to_sign, HASH_ALGO) + .unwrap() + .into_iter() + .map(Some) + .collect::>(); + + Some(sign) + } else { + None + }; + + let sig_pairs = signatures + .unwrap_or_else(|| vec![None; shares_count as usize]) + .into_iter() + .map(|sig_pair| sig_pair.map(From::from)); + + let shares_and_sigs = shares.into_iter().enumerate().zip(sig_pairs); + + let result = shares_and_sigs.map(|((index, data), signature_pair)| { + // This is actually safe since we alwaays generate less than 256 shares. + let id = (index + 1) as u8; + + Share { + id, + threshold, + data, + signature_pair, + } + }); + + Ok(result.collect()) + } + + fn secret_share(src: &[u8], threshold: u8, shares_count: u8) -> Result>> { + let mut result = Vec::with_capacity(shares_count as usize); + for _ in 0..(shares_count as usize) { + result.push(vec![0u8; src.len()]); + } + let mut col_in = vec![0u8, threshold]; + let mut col_out = Vec::with_capacity(shares_count as usize); + let mut osrng = OsRng::new()?; + for (c, &s) in src.iter().enumerate() { + col_in[0] = s; + osrng.fill_bytes(&mut col_in[1..]); + col_out.clear(); + encode_secret_byte(&*col_in, shares_count, &mut col_out)?; + for (&y, share) in col_out.iter().zip(result.iter_mut()) { + share[c] = y; + } + } + Ok(result) + } + + /// Recovers the secret from a k-out-of-n Shamir's secret sharing. + /// + /// At least `k` distinct shares need to be provided to recover the share. + pub fn recover_secret(shares: Vec, verify_signatures: bool) -> Result> { + let (threshold, shares) = validate_signed_shares(shares, verify_signatures)?; + + let slen = shares[0].data.len(); + let mut col_in = Vec::with_capacity(threshold as usize); + let mut secret = Vec::with_capacity(slen); + for byteindex in 0..slen { + col_in.clear(); + for s in shares.iter().take(threshold as usize) { + col_in.push((s.id, s.data[byteindex])); + } + secret.push(interpolate_at(&*col_in)); + } + + Ok(secret) + } +} diff --git a/src/sss/share.rs b/src/sss/share.rs new file mode 100644 index 0000000..f46ad67 --- /dev/null +++ b/src/sss/share.rs @@ -0,0 +1,177 @@ +use std::error::Error; +use std::collections::{HashMap, HashSet}; + +use merkle_sigs::{MerklePublicKey, Proof}; +use merkle_sigs::verify_data_vec_signature; + +use errors::*; +use share::{IsShare, IsSignedShare}; +use sss::format::{format_share_for_signing, share_from_string, share_to_string}; + +/// A share identified by an `id`, a threshold `k`, a number of total shares `n`, +/// the `data` held in the share, and the share's `metadata`. +// #[derive(Clone, Debug, Hash, PartialEq, Eq)] +// TODO: Write manual instances which ignore the signature / fix merkle_sigs+merkle.rs +#[derive(Clone, Debug)] +pub(crate) struct Share { + /// The identifier of the share (varies between 1 and n where n is the total number of generated shares) + pub id: u8, + /// The number of shares necessary to recover the secret, aka a threshold + pub threshold: u8, + /// The share data itself + pub data: Vec, + /// If the share is signed, this fields holds the signature + /// along with the proof of inclusion into the underlying MerkleTree. + pub signature_pair: Option, +} + +impl Share { + /// Attempts to parse the given string into a share which should have the given `id`. + /// The string `raw` should follow the format of `Share::into_string`. + pub(crate) fn from_string(raw: &str, is_signed: bool) -> Result { + share_from_string(raw, is_signed) + } + + /// Attempts to parse all the given strings into shares. + /// Calls out to `Share::from_string`. + pub(crate) fn parse_all(raws: &[String], is_signed: bool) -> Result> { + raws.into_iter() + .map(|raw| Self::from_string(raw, is_signed)) + .collect() + } + + /// Format the share as a string suitable for being stored in a file. + /// The format is the following: + /// + /// ```text + /// 2-1-LiTyeXwEP71IUA + /// ^ ^ ^^^^^^^^^^^^^^ + /// K N D + /// + /// It is built out of three parts separated with a dash: K-N-D. + /// + /// - K specifies the number of shares necessary to recover the secret. + /// - N is the identifier of the share and varies between 1 and n where + /// n is the total number of generated shares. + /// - D is a Base64 encoding of a ShareData protobuf containing + /// information about the share, and if signed, the signature. + /// ``` + pub fn into_string(self) -> String { + share_to_string( + self.data, + self.threshold, + self.id, + self.signature_pair.map(Into::into), + ) + } +} + +impl IsShare for Share { + fn get_id(&self) -> u8 { + self.id + } + + fn get_data(&self) -> &[u8] { + &self.data + } + + fn get_threshold(&self) -> u8 { + self.threshold + } + + fn get_shares_count(&self) -> Option { + None + } +} + +impl IsSignedShare for Share { + type Signature = Option; + + fn verify_signatures(shares: &[Self]) -> Result<()> { + let mut rh_compatibility_sets = HashMap::new(); + + for share in shares { + if !share.is_signed() { + bail!(ErrorKind::MissingSignature(share.get_id())); + } + + let sig_pair = share.signature_pair.as_ref().unwrap(); + let signature = &sig_pair.signature; + let proof = &sig_pair.proof; + let root_hash = &proof.root_hash; + + verify_data_vec_signature( + format_share_for_signing(share.threshold, share.id, share.data.as_slice()), + &(signature.to_vec(), proof.clone()), + root_hash, + ).map_err(|e| ErrorKind::InvalidSignature(share.id, String::from(e.description())))?; + + rh_compatibility_sets + .entry(root_hash) + .or_insert_with(HashSet::new); + + let rh_set = rh_compatibility_sets.get_mut(&root_hash).unwrap(); + rh_set.insert(share.id); + } + + let rh_sets = rh_compatibility_sets.keys().count(); + + match rh_sets { + 0 => bail!(ErrorKind::EmptyShares), + 1 => {} // All shares have the same roothash. + _ => { + bail! { + ErrorKind::IncompatibleSets( + rh_compatibility_sets + .values() + .map(|x| x.to_owned()) + .collect(), + ) + } + } + } + + Ok(()) + } + + fn is_signed(&self) -> bool { + self.signature_pair.is_some() + } + + fn get_signature(&self) -> &Self::Signature { + &self.signature_pair + } +} + +#[derive(Clone, Debug)] +/// Holds the signature along with the proof of inclusion +/// in the underlying Merkle tree used in the Lamport signature scheme. +pub struct SignaturePair { + /// The signature + pub signature: Vec>, + /// The proof of inclusion + pub proof: Proof, +} + +impl From for (Vec>, Proof) { + fn from(pair: SignaturePair) -> Self { + (pair.signature, pair.proof) + } +} + +impl From<(Vec>, Proof)> for SignaturePair { + fn from(pair: (Vec>, Proof)) -> Self { + Self { + signature: pair.0, + proof: pair.1, + } + } +} + +// TODO: Uncomment when re-implementating standard traits for `Share` +// impl Hash for SignaturePair { +// fn hash(&self, state: &mut H) { +// self.signature.hash(state); +// self.proof.root_hash.hash(state); +// } +// } diff --git a/src/tests/mod.rs b/src/tests/mod.rs deleted file mode 100644 index 11f29a3..0000000 --- a/src/tests/mod.rs +++ /dev/null @@ -1 +0,0 @@ -mod test_vectors; diff --git a/src/validation.rs b/src/validation.rs deleted file mode 100644 index b57769d..0000000 --- a/src/validation.rs +++ /dev/null @@ -1,102 +0,0 @@ -use custom_error::{RustyError, RustyErrorTypes}; -use merkle_sigs::verify_data_vec_signature; -use share_format; -use share_format::format_share_for_signing; -use std::collections::HashMap; -use std::error::Error; - -type ProcessedShares = Result<(u8, Vec<(u8, Vec)>), RustyError>; - -// The order of validation that we think makes the most sense is the following: -// 1) Validate shares individually -// 2) Validate duplicate shares share num && data -// 2) Validate group consistency -// 3) Validate other properties, in no specific order - -pub fn process_and_validate_shares(shares_strings: Vec, - verify_signatures: bool) - -> ProcessedShares { - let mut shares: Vec<(u8, Vec)> = Vec::new(); - - let mut k_compatibility_sets = HashMap::new(); - let mut rh_compatibility_sets = HashMap::new(); - - for (counter, line) in shares_strings.iter().enumerate() { - let share_index = counter as u8; - let (share_data, k, n, sig_pair) = try!(share_format::share_from_string(line, - counter as u8, - verify_signatures)); - if verify_signatures { - if sig_pair.is_none() { - return Err(RustyError::with_type(RustyErrorTypes::MissingSignature(share_index))); - } - - let (signature, p) = sig_pair.unwrap(); - let root_hash = p.root_hash.clone(); - - try!(verify_data_vec_signature(format_share_for_signing(k, - n, - &share_data.as_slice()), - &(signature.to_vec(), p), - &root_hash) - .map_err(|e| RustyError::with_type(RustyErrorTypes::InvalidSignature(share_index, String::from(e.description()))))); - rh_compatibility_sets.entry(root_hash.clone()).or_insert_with(Vec::new); - let vec = rh_compatibility_sets.get_mut(&root_hash).unwrap(); - vec.push(share_index); - } - - k_compatibility_sets.entry(k).or_insert_with(Vec::new); - let vec = k_compatibility_sets.get_mut(&k).unwrap(); - vec.push(share_index); - - if shares.iter().any(|s| s.0 == n) { - return Err(RustyError::with_type(RustyErrorTypes::DuplicateShareNum(share_index))); - }; - - if shares.iter().any(|s| s.1 == share_data) && k != 1 { // When k = 1, shares data can be the same - return Err(RustyError::with_type(RustyErrorTypes::DuplicateShareData(share_index))); - }; - - shares.push((n, share_data)); - } - - // Validate k - - let k_sets = k_compatibility_sets.keys().count(); - let rh_sets = rh_compatibility_sets.keys().count(); - - if verify_signatures { - match rh_sets { - 0 => { - return Err(RustyError::with_type(RustyErrorTypes::EmptyShares)) - } - 1 => { } // All shares have the same roothash. - _ => { - return Err(RustyError::with_type(RustyErrorTypes::IncompatibleSets(rh_compatibility_sets.values() - .map(|x| x.to_owned()).collect()))) - } - } - } - - match k_sets { - 0 => { - return Err(RustyError::with_type(RustyErrorTypes::EmptyShares)) - } - 1 => { } // All shares have the same roothash. - _ => { - return Err(RustyError::with_type(RustyErrorTypes::IncompatibleSets(k_compatibility_sets.values() - .map(|x| x.to_owned()).collect()))) - } - } - - // It is safe to unwrap because k_sets == 1 - let k = *k_compatibility_sets.keys().last().unwrap(); - let shares_num = shares.len(); - - if shares_num >= k as usize { - shares.truncate(k as usize); - Ok((k, shares)) - } else { - Err(RustyError::with_type(RustyErrorTypes::MissingShares(k, shares_num))) - } -} diff --git a/src/vol_hash.rs b/src/vol_hash.rs new file mode 100644 index 0000000..1db0310 --- /dev/null +++ b/src/vol_hash.rs @@ -0,0 +1,55 @@ +use std; +use std::mem::transmute; + +use ring::digest::{Algorithm, Context}; + +#[allow(unsafe_code)] +fn u32_to_bytes(x: u32) -> [u8; 4] { + unsafe { transmute(x.to_be()) } +} + +pub struct VOLHash { + algorithm: &'static Algorithm, + bytes: Vec, +} + +impl VOLHash { + pub fn new(algorithm: &'static Algorithm) -> VOLHash { + Self { + algorithm, + bytes: Vec::new(), + } + } + + pub fn process(&mut self, bytes: &[u8]) { + self.bytes.extend_from_slice(bytes) + } + + pub fn finish(self, dest: &mut [u8]) { + let len = dest.len(); + assert!(len < std::u32::MAX as usize); + + let mut ctx = Context::new(self.algorithm); + ctx.update(&[0u8]); + ctx.update(&u32_to_bytes(len as u32)); + ctx.update(&self.bytes); + + let mut state = ctx.finish().as_ref().to_vec(); + + let iter_num = len / self.algorithm.output_len; + + for i in 0..iter_num { + let mut inner_ctx = Context::new(self.algorithm); + inner_ctx.update(&[255u8]); + inner_ctx.update(&u32_to_bytes(1 + i as u32)); + inner_ctx.update(&state); + + state.extend_from_slice(inner_ctx.finish().as_ref()) + } + + assert!(state.len() >= len); + + let src = state.drain(0..len).collect::>(); + dest.copy_from_slice(&src); + } +} diff --git a/src/wrapped_secrets.rs b/src/wrapped_secrets.rs deleted file mode 100644 index ea205da..0000000 --- a/src/wrapped_secrets.rs +++ /dev/null @@ -1,64 +0,0 @@ -//! (Beta) `wrapped_secrets` provides Shamir's secret sharing with a wrapped secret. It currently offers versioning and MIME information about the data. - -use custom_error::{RustyError, RustyErrorTypes}; -use protobuf; -use protobuf::Message; -use secret::{RustySecret, RustySecretsVersions}; -use sss; -use std::io; - -/// Performs threshold k-out-of-n Shamir's secret sharing. -/// -/// # Examples -/// -/// ``` -/// use rusty_secrets::wrapped_secrets::generate_shares; -/// let secret = "These programs were never about terrorism: they’re about economic spying, -/// social control, and diplomatic manipulation. They’re about power.".to_string(); -/// -/// match generate_shares(7, 10, &secret.into_bytes(), Some("text/html".to_string()), true){ -/// Ok(shares) => { -/// // Do something with the shares -/// }, -/// Err(_) => {}// Deal with error} -/// } -/// ``` -pub fn generate_shares(k: u8, n: u8, secret: &[u8], mime_type: Option, sign_shares: bool) -> io::Result> { - let mut rusty_secret = RustySecret::new(); - rusty_secret.set_version(RustySecretsVersions::INITIAL_RELEASE); - rusty_secret.set_secret(secret.to_owned()); - - for mt in mime_type { - rusty_secret.set_mime_type(mt); - } - - sss::generate_shares(k, n, rusty_secret.write_to_bytes().unwrap().as_slice(), sign_shares) -} - -/// Recovers the secret from a k-out-of-n Shamir's secret sharing. -/// -/// At least `k` distinct shares need to be provided to recover the share. -/// -/// # Examples -/// -/// ``` -/// use rusty_secrets::wrapped_secrets::recover_secret; -/// let share1 = "2-1-Cha7s14Q/mSwWko0ittr+/Uf79RHQMIP".to_string(); -/// let share2 = "2-4-ChaydsUJDypD9ZWxwvIICh/cmZvzusOF".to_string(); -/// let shares = vec![share1, share2]; -/// -/// match recover_secret(shares, false) { -/// Ok(secret) => { -/// // Do something with the secret -/// }, -/// Err(e) => { -/// // Deal with the error -/// } -/// } -/// ``` -pub fn recover_secret(shares: Vec, verify_signatures: bool) -> Result { - let secret = try!(sss::recover_secret(shares, verify_signatures)); - - protobuf::parse_from_bytes::(secret.as_slice()) - .map_err(|_| RustyError::with_type(RustyErrorTypes::SecretDeserializationIssue)) -} diff --git a/src/wrapped_secrets/mod.rs b/src/wrapped_secrets/mod.rs new file mode 100644 index 0000000..3a797fd --- /dev/null +++ b/src/wrapped_secrets/mod.rs @@ -0,0 +1,73 @@ +//! (Beta) `wrapped_secrets` provides Shamir's secret sharing with a wrapped secret. It currently offers versioning and MIME information about the data. + +use errors::*; +use proto::wrapped::SecretProto; + +mod scheme; +pub(crate) use self::scheme::*; + +/// Performs threshold k-out-of-n Shamir's secret sharing. +/// +/// # Examples +/// +/// ``` +/// use rusty_secrets::wrapped_secrets::split_secret; +/// +/// let secret = "These programs were never about terrorism: they’re about economic spying, \ +/// social control, and diplomatic manipulation. They’re about power."; +/// +/// let result = split_secret( +/// 7, +/// 10, +/// &secret.as_bytes(), +/// Some("text/html".to_string()), +/// true, +/// ); +/// +/// match result { +/// Ok(shares) => { +/// // Do something with the shares +/// }, +/// Err(_) => { +/// // Deal with error +/// } +/// } +/// ``` +pub fn split_secret( + k: u8, + n: u8, + secret: &[u8], + mime_type: Option, + sign_shares: bool, +) -> Result> { + WrappedSecrets::default() + .split_secret(k, n, secret, mime_type, sign_shares) + .map(|shares| shares.into_iter().map(Share::into_string).collect()) +} + +/// Recovers the secret from a k-out-of-n Shamir's secret sharing. +/// +/// At least `k` distinct shares need to be provided to recover the share. +/// +/// # Examples +/// +/// ```rust +/// use rusty_secrets::wrapped_secrets::recover_secret; +/// +/// let share1 = "2-1-Cha7s14Q/mSwWko0ittr+/Uf79RHQMIP".to_string(); +/// let share2 = "2-4-ChaydsUJDypD9ZWxwvIICh/cmZvzusOF".to_string(); +/// let shares = vec![share1, share2]; +/// +/// match recover_secret(&shares, false) { +/// Ok(secret) => { +/// // Do something with the secret +/// }, +/// Err(e) => { +/// // Deal with the error +/// } +/// } +/// ``` +pub fn recover_secret(shares: &[String], verify_signatures: bool) -> Result { + let shares = Share::parse_all(shares, verify_signatures)?; + WrappedSecrets::recover_secret(shares, verify_signatures) +} diff --git a/src/wrapped_secrets/scheme.rs b/src/wrapped_secrets/scheme.rs new file mode 100644 index 0000000..27b2e54 --- /dev/null +++ b/src/wrapped_secrets/scheme.rs @@ -0,0 +1,45 @@ +use errors::*; +use protobuf; +use protobuf::Message; +use proto::VersionProto; +use proto::wrapped::SecretProto; + +use sss::SSS; +pub(crate) use sss::Share; + +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] +pub(crate) struct WrappedSecrets; + +impl WrappedSecrets { + /// Performs threshold k-out-of-n Shamir's secret sharing. + pub fn split_secret( + &self, + k: u8, + n: u8, + secret: &[u8], + mime_type: Option, + sign_shares: bool, + ) -> Result> { + let mut rusty_secret = SecretProto::new(); + rusty_secret.set_version(VersionProto::INITIAL_RELEASE); + rusty_secret.set_secret(secret.to_owned()); + + if let Some(mt) = mime_type { + rusty_secret.set_mime_type(mt); + } + + let data = rusty_secret.write_to_bytes().unwrap(); + + SSS::default().split_secret(k, n, data.as_slice(), sign_shares) + } + + /// Recovers the secret from a k-out-of-n Shamir's secret sharing. + /// + /// At least `k` distinct shares need to be provided to recover the share. + pub fn recover_secret(shares: Vec, verify_signatures: bool) -> Result { + let secret = SSS::recover_secret(shares, verify_signatures)?; + + protobuf::parse_from_bytes::(secret.as_slice()) + .chain_err(|| ErrorKind::SecretDeserializationError) + } +} diff --git a/tests/fixtures/gf256/.gitignore b/tests/fixtures/gf256/.gitignore new file mode 100644 index 0000000..4fbc60b --- /dev/null +++ b/tests/fixtures/gf256/.gitignore @@ -0,0 +1,3 @@ +*.py +*.pyc +*.sage.py diff --git a/tests/fixtures/gf256/Makefile b/tests/fixtures/gf256/Makefile new file mode 100644 index 0000000..8175c36 --- /dev/null +++ b/tests/fixtures/gf256/Makefile @@ -0,0 +1,18 @@ + +SAGE = sage + +TARGETS = gf256_add.txt.gz gf256_sub.txt.gz gf256_div.txt.gz gf256_mul.txt.gz gf256_pow.txt.gz + +.PHONY: all clean + +all: $(TARGETS) + +%.txt.gz: %.sage common.py + $(SAGE) $< | gzip > $@ + +common.py: common.sage + $(SAGE) --preparse $< + mv common.sage.py common.py + +clean: + $(RM) $(TARGETS) common.py diff --git a/tests/fixtures/gf256/common.sage b/tests/fixtures/gf256/common.sage new file mode 100644 index 0000000..82e7d30 --- /dev/null +++ b/tests/fixtures/gf256/common.sage @@ -0,0 +1,2 @@ + +field = GF(2**8, name='a', modulus=x^8+x^4+x^3+x^2+1, repr='int') diff --git a/tests/fixtures/gf256/gf256_add.sage b/tests/fixtures/gf256/gf256_add.sage new file mode 100644 index 0000000..6800739 --- /dev/null +++ b/tests/fixtures/gf256/gf256_add.sage @@ -0,0 +1,5 @@ +from common import field + +for i in sorted(field): + for j in sorted(field): + print("{} + {} = {}".format(i, j, i + j)) diff --git a/tests/fixtures/gf256/gf256_add.txt.gz b/tests/fixtures/gf256/gf256_add.txt.gz new file mode 100644 index 0000000..7aa17cc Binary files /dev/null and b/tests/fixtures/gf256/gf256_add.txt.gz differ diff --git a/tests/fixtures/gf256/gf256_div.sage b/tests/fixtures/gf256/gf256_div.sage new file mode 100644 index 0000000..6003f02 --- /dev/null +++ b/tests/fixtures/gf256/gf256_div.sage @@ -0,0 +1,5 @@ +from common import field + +for i in sorted(field): + for j in sorted(field)[1:]: + print("{} / {} = {}".format(i, j, i / j)) diff --git a/tests/fixtures/gf256/gf256_div.txt.gz b/tests/fixtures/gf256/gf256_div.txt.gz new file mode 100644 index 0000000..dfdc364 Binary files /dev/null and b/tests/fixtures/gf256/gf256_div.txt.gz differ diff --git a/tests/fixtures/gf256/gf256_mul.sage b/tests/fixtures/gf256/gf256_mul.sage new file mode 100644 index 0000000..4aec4a5 --- /dev/null +++ b/tests/fixtures/gf256/gf256_mul.sage @@ -0,0 +1,5 @@ +from common import field + +for i in sorted(field): + for j in sorted(field): + print("{} * {} = {}".format(i, j, i * j)) diff --git a/tests/fixtures/gf256/gf256_mul.txt.gz b/tests/fixtures/gf256/gf256_mul.txt.gz new file mode 100644 index 0000000..6c6df42 Binary files /dev/null and b/tests/fixtures/gf256/gf256_mul.txt.gz differ diff --git a/tests/fixtures/gf256/gf256_pow.sage b/tests/fixtures/gf256/gf256_pow.sage new file mode 100644 index 0000000..5c3f9ee --- /dev/null +++ b/tests/fixtures/gf256/gf256_pow.sage @@ -0,0 +1,5 @@ +from common import field + +for i in sorted(field): + for j in range(0, 256): + print("{} ^ {} = {}".format(i, j, i ^ j)) diff --git a/tests/fixtures/gf256/gf256_pow.txt.gz b/tests/fixtures/gf256/gf256_pow.txt.gz new file mode 100644 index 0000000..cf719c8 Binary files /dev/null and b/tests/fixtures/gf256/gf256_pow.txt.gz differ diff --git a/tests/fixtures/gf256/gf256_sub.sage b/tests/fixtures/gf256/gf256_sub.sage new file mode 100644 index 0000000..dd72bec --- /dev/null +++ b/tests/fixtures/gf256/gf256_sub.sage @@ -0,0 +1,5 @@ +from common import field + +for i in sorted(field): + for j in sorted(field): + print("{} - {} = {}".format(i, j, i - j)) diff --git a/tests/fixtures/gf256/gf256_sub.txt.gz b/tests/fixtures/gf256/gf256_sub.txt.gz new file mode 100644 index 0000000..4d37bb7 Binary files /dev/null and b/tests/fixtures/gf256/gf256_sub.txt.gz differ diff --git a/tests/generation_errors.rs b/tests/generation_errors.rs index 2d4f156..21634d0 100644 --- a/tests/generation_errors.rs +++ b/tests/generation_errors.rs @@ -1,11 +1,11 @@ extern crate rusty_secrets; -use rusty_secrets::sss::generate_shares; +use rusty_secrets::sss; #[test] -#[should_panic(expected = "Threshold K can not be larger than N")] +#[should_panic(expected = "ThresholdTooBig")] fn test_generate_invalid_k() { let share1 = "2-1-1YAYwmOHqZ69jA".to_string().into_bytes(); - generate_shares(10, 5, share1.as_slice(), true).unwrap(); + sss::split_secret(10, 5, share1.as_slice(), true).unwrap(); } diff --git a/tests/randomized_tests.rs b/tests/randomized_tests.rs index 2a15b34..fedd801 100644 --- a/tests/randomized_tests.rs +++ b/tests/randomized_tests.rs @@ -1,6 +1,6 @@ extern crate rusty_secrets; -use rusty_secrets::*; +use rusty_secrets::wrapped_secrets; #[ignore] #[test] @@ -19,12 +19,17 @@ fn test_reasonable_splits() { for is_signing in &[true, false] { for k in 1..max_shares { for n in k..max_shares { - let shares = wrapped_secrets::generate_shares(k, n, &secret, Some(mime_type.clone()), *is_signing).unwrap(); + let shares = wrapped_secrets::split_secret( + k, + n, + &secret, + Some(mime_type.clone()), + *is_signing, + ).unwrap(); println!("Testing {} out-of- {}", k, n); - let s = wrapped_secrets::recover_secret(shares, *is_signing).unwrap(); + let s = wrapped_secrets::recover_secret(&shares, *is_signing).unwrap(); assert_eq!(s.get_secret().to_owned(), secret); - assert!(s.has_mime_type()); assert_eq!(mime_type, s.get_mime_type()); } } diff --git a/tests/recovery_errors.rs b/tests/recovery_errors.rs index a836083..131a012 100644 --- a/tests/recovery_errors.rs +++ b/tests/recovery_errors.rs @@ -3,92 +3,87 @@ extern crate rusty_secrets; use rusty_secrets::sss::recover_secret; #[test] -#[should_panic(expected = "No shares were provided.")] +#[should_panic(expected = "EmptyShares")] fn test_recover_no_shares() { - let shares = vec![]; - recover_secret(shares, false).unwrap(); + for signed in &[true, false] { + let shares = vec![]; + recover_secret(&shares, *signed).unwrap(); + } } #[test] -#[should_panic(expected = "No shares were provided.")] -fn test_recover_no_shares_signed() { - let shares = vec![]; - recover_secret(shares, true).unwrap(); -} - -#[test] -#[should_panic(expected = "This share is incorrectly formatted.")] +#[should_panic(expected = "ShareParsingError")] fn test_recover_2_parts_share() { let share1 = "2-1-CgmKQZHMO+5n5pU".to_string(); let share2 = "2-2".to_string(); let shares = vec![share1, share2]; - recover_secret(shares, false).unwrap(); + recover_secret(&shares, false).unwrap(); } #[test] -#[should_panic(expected = "Integer parsing error")] +#[should_panic(expected = "IntegerParsingError")] fn test_recover_incorrect_share_num() { let share1 = "2-1-CgnlCxRNtnkzENE".to_string(); let share2 = "2-DEFINITLY_NAN-CgkAnUgP3lfwjyM".to_string(); let shares = vec![share1, share2]; - recover_secret(shares, false).unwrap(); + recover_secret(&shares, false).unwrap(); } #[test] -#[should_panic(expected = "This share is incorrectly formatted.")] +#[should_panic(expected = "ShareParsingError")] fn test_recover_0_share_num() { let share1 = "2-0-1YAYwmOHqZ69jA".to_string(); let share2 = "2-1-YJZQDGm22Y77Gw".to_string(); let shares = vec![share1, share2]; - recover_secret(shares, false).unwrap(); + recover_secret(&shares, false).unwrap(); } #[test] -#[should_panic(expected = "This share is incorrectly formatted.")] +#[should_panic(expected = "ShareParsingError")] fn test_recover_invalid_b64() { let share1 = "2-1-CgnlCxRNtnkzENE".to_string(); - let share2 = "2-1-YJZQDG((((m22Y)))77Gw".to_string(); + let share2 = "2-2-YJZQDG((((m22Y)))77Gw".to_string(); let shares = vec![share1, share2]; - recover_secret(shares, false).unwrap(); + recover_secret(&shares, false).unwrap(); } #[test] -#[should_panic(expected = "This share number has already been used by a previous share.")] +#[should_panic(expected = "DuplicateShareId")] fn test_recover_duplicate_shares_number() { let share1 = "2-1-CgnlCxRNtnkzENE".to_string(); let share2 = "2-1-CgkAnUgP3lfwjyM".to_string(); let shares = vec![share1, share2]; - recover_secret(shares, false).unwrap(); + recover_secret(&shares, false).unwrap(); } #[test] -#[should_panic(expected = "The data encoded in this share is the same as the one found in a previous share.")] +#[should_panic(expected = "DuplicateShareData")] fn test_recover_duplicate_shares_data() { let share1 = "2-1-CgnlCxRNtnkzENE".to_string(); let share2 = "2-2-CgnlCxRNtnkzENE".to_string(); let shares = vec![share1, share2]; - recover_secret(shares, false).unwrap(); + recover_secret(&shares, false).unwrap(); } #[test] -#[should_panic(expected = "The number of shares provided is insufficient to recover the secret.")] +#[should_panic(expected = "MissingShares")] fn test_recover_too_few_shares() { let share1 = "3-1-ChbcCdSZOaMn6DM1jFca2P6/0WRlP7AK".to_string(); let share2 = "3-2-ChbG46L1zRszs0PPn63XnnupmZTcgYJ3".to_string(); let shares = vec![share1, share2]; - recover_secret(shares, false).unwrap(); + recover_secret(&shares, false).unwrap(); } diff --git a/tests/ss1_recovery_errors.rs b/tests/ss1_recovery_errors.rs new file mode 100644 index 0000000..4ab71a2 --- /dev/null +++ b/tests/ss1_recovery_errors.rs @@ -0,0 +1,188 @@ +#![cfg(feature = "dss")] + +extern crate rusty_secrets; +use rusty_secrets::dss::ss1::{recover_secret, split_secret, Reproducibility, Share}; + +const TEST_THRESHOLD: u8 = 2; +const TEST_SHARES_COUNT: u8 = 2; +const TEST_REPRODUCIBILITY: Reproducibility = Reproducibility::Reproducible; +const TEST_SECRET: &[u8] = + b"These programs were never about terrorism: they're about economic spying, \ + social control, and diplomatic manipulation. They're about power."; + +fn get_test_hash() -> Vec { + let good_shares = split_secret( + TEST_THRESHOLD, + TEST_SHARES_COUNT, + TEST_SECRET, + TEST_REPRODUCIBILITY, + &None, + ).unwrap(); + + good_shares[0].hash.clone() +} + +#[test] +#[should_panic(expected = "EmptyShares")] +fn test_recover_no_shares() { + let shares = vec![]; + recover_secret(&shares).unwrap(); +} + +#[test] +#[should_panic(expected = "ShareParsingErrorEmptyShare")] +fn test_recover_2_parts_share() { + let hash = get_test_hash(); + + let share1 = Share { + id: 1, + threshold: TEST_THRESHOLD, + shares_count: TEST_SHARES_COUNT, + data: "CgmKQZHMO+5n5pU".to_string().into_bytes(), + hash: hash.clone(), + metadata: None, + }; + let share2 = Share { + id: 2, + threshold: TEST_THRESHOLD, + shares_count: TEST_SHARES_COUNT, + data: "".to_string().into_bytes(), + hash: hash.clone(), + metadata: None, + }; + + let shares = vec![share1, share2]; + + recover_secret(&shares).unwrap(); +} + +#[test] +#[should_panic(expected = "ShareParsingInvalidShareId")] +fn test_recover_0_share_num() { + let hash = get_test_hash(); + + let share1 = Share { + id: 0, + threshold: TEST_THRESHOLD, + shares_count: TEST_SHARES_COUNT, + data: "1YAYwmOHqZ69jA".to_string().into_bytes(), + hash: hash.clone(), + metadata: None, + }; + let share2 = Share { + id: 1, + threshold: TEST_THRESHOLD, + shares_count: TEST_SHARES_COUNT, + data: "YJZQDGm22Y77Gw".to_string().into_bytes(), + hash: hash.clone(), + metadata: None, + }; + + let shares = vec![share1, share2]; + + recover_secret(&shares).unwrap(); +} + +// --- +// TODO: will be implemented when serialization is done for ss1 shares +// --- +// #[test] +// #[should_panic(expected = "ShareParsingError")] +// fn test_recover_invalid_b64() { +// let share1 = Share { +// id: 1, +// threshold: 2, +// shares_count: 2, +// data: "1YAYwmOHqZ69jA".to_string().into_bytes(), +// metadata: None +// }; +// let share2 = Share { +// id: 2, +// threshold: 2, +// shares_count: 2, +// data: "YJZQDG((((m22Y)))77Gw".to_string().into_bytes(), +// metadata: None +// }; +// +// let shares = vec![share1, share2]; +// +// recover_secret(&shares).unwrap(); +// } + +#[test] +#[should_panic(expected = "DuplicateShareId")] +fn test_recover_duplicate_shares_number() { + let hash = get_test_hash(); + let share1 = Share { + id: 1, + threshold: TEST_THRESHOLD, + shares_count: TEST_SHARES_COUNT, + data: "1YAYwmOHqZ69jA".to_string().into_bytes(), + hash: hash.clone(), + metadata: None, + }; + let share2 = Share { + id: 1, + threshold: TEST_THRESHOLD, + shares_count: TEST_SHARES_COUNT, + data: "YJZQDGm22Y77Gw".to_string().into_bytes(), + hash: hash.clone(), + metadata: None, + }; + + let shares = vec![share1, share2]; + + recover_secret(&shares).unwrap(); +} + +#[test] +#[should_panic(expected = "DuplicateShareData")] +fn test_recover_duplicate_shares_data() { + let hash = get_test_hash(); + let share1 = Share { + id: 1, + threshold: TEST_THRESHOLD, + shares_count: TEST_SHARES_COUNT, + data: "1YAYwmOHqZ69jA".to_string().into_bytes(), + hash: hash.clone(), + metadata: None, + }; + let share2 = Share { + id: 2, + threshold: TEST_THRESHOLD, + shares_count: TEST_SHARES_COUNT, + data: "1YAYwmOHqZ69jA".to_string().into_bytes(), + hash: hash.clone(), + metadata: None, + }; + + let shares = vec![share1, share2]; + + recover_secret(&shares).unwrap(); +} + +#[test] +#[should_panic(expected = "MissingShares")] +fn test_recover_too_few_shares() { + let hash = get_test_hash(); + let share1 = Share { + id: 1, + threshold: TEST_THRESHOLD + 1, + shares_count: TEST_SHARES_COUNT + 1, + data: "1YAYwmOHqZ69jA".to_string().into_bytes(), + hash: hash.clone(), + metadata: None, + }; + let share2 = Share { + id: 2, + threshold: TEST_THRESHOLD + 1, + shares_count: TEST_SHARES_COUNT + 1, + data: "YJZQDGm22Y77Gw".to_string().into_bytes(), + hash: hash.clone(), + metadata: None, + }; + + let shares = vec![share1, share2]; + + recover_secret(&shares).unwrap(); +} diff --git a/src/tests/test_vectors.rs b/tests/test_vectors.rs similarity index 52% rename from src/tests/test_vectors.rs rename to tests/test_vectors.rs index 9fa2ab6..3be698c 100644 --- a/src/tests/test_vectors.rs +++ b/tests/test_vectors.rs @@ -1,21 +1,22 @@ +extern crate base64; extern crate protobuf; -extern crate rustc_serialize as serialize; +extern crate rusty_secrets; use protobuf::Message; -use share_data; -use sss::recover_secret; -use serialize::base64::{self, FromBase64, ToBase64}; + +use rusty_secrets::proto::wrapped::ShareProto; +use rusty_secrets::sss::recover_secret; + +const BASE64_CONFIG: base64::Config = base64::STANDARD_NO_PAD; pub fn wrap_from_sellibitze(share: &str) -> String { let parts: Vec<_> = share.trim().split('-').collect(); - let share_data = parts[2].from_base64().unwrap(); + let share_data = base64::decode_config(parts[2], BASE64_CONFIG).unwrap(); - let config = base64::Config { pad: false, ..base64::STANDARD }; - - let mut share_protobuf = share_data::ShareData::new(); + let mut share_protobuf = ShareProto::new(); share_protobuf.set_shamir_data(share_data); - let b64_share = share_protobuf.write_to_bytes().unwrap().to_base64(config); + let b64_share = base64::encode_config(&share_protobuf.write_to_bytes().unwrap(), BASE64_CONFIG); format!("{}-{}-{}", parts[0], parts[1], b64_share) } @@ -25,48 +26,47 @@ fn test_recover_sellibitze() { let share1 = "2-1-1YAYwmOHqZ69jA"; let share2 = "2-4-F7rAjX3UOa53KA"; - let shares = vec![share1, share2].iter().map(|x| wrap_from_sellibitze(x)).collect::>(); + let shares = vec![share1, share2] + .iter() + .map(|x| wrap_from_sellibitze(x)) + .collect::>(); let mut secret = "My secret".to_string().into_bytes(); secret.push(10); - assert_eq!(recover_secret(shares, false).unwrap(), secret); + assert_eq!(recover_secret(&shares, false).unwrap(), secret); } // Generated with code on master branch on the 6th of April. #[test] fn test_recover_es_test_vectors() { let share1 = - "5-1-DbuicpLQiCf7bVWiAz8eCpQGpdZmYQ7z2j2+g351tWFLOQPTZkXY8BYfwGGGjkOoz1g9x0ScmLFcWk+2tign" - .to_string(); + "5-1-DbuicpLQiCf7bVWiAz8eCpQGpdZmYQ7z2j2+g351tWFLOQPTZkXY8BYfwGGGjkOoz1g9x0ScmLFcWk+2tign"; let share2 = - "5-2-nShdfkY5+SlfybMyqjHXCZ01bq5N/0Lkf0nQZw5x3bnHIEVfa0RA4YcJ4SjG/UdpgO/gOcyLRkSp2Dwf8bvw" - .to_string(); + "5-2-nShdfkY5+SlfybMyqjHXCZ01bq5N/0Lkf0nQZw5x3bnHIEVfa0RA4YcJ4SjG/UdpgO/gOcyLRkSp2Dwf8bvw"; let share3 = - "5-3-qEhJ3IVEdbDkiRoy+jOJ/KuGE9jWyGeOYEcDwPfEV8E9rfD1Bc17BQAbJ51Xd8oexS2M1qMvNgJHZUQZbUgQ" - .to_string(); + "5-3-qEhJ3IVEdbDkiRoy+jOJ/KuGE9jWyGeOYEcDwPfEV8E9rfD1Bc17BQAbJ51Xd8oexS2M1qMvNgJHZUQZbUgQ"; let share4 = - "5-6-yyVPUeaYPPiWK0wIV5OQ/t61V0lSEO+7X++EWeHRlIq3sRBNwUpKNfx/C+Vc9xTzUftrqBKvkWDZQal7nyi2" - .to_string(); + "5-6-yyVPUeaYPPiWK0wIV5OQ/t61V0lSEO+7X++EWeHRlIq3sRBNwUpKNfx/C+Vc9xTzUftrqBKvkWDZQal7nyi2"; let share5 = - "5-7-i8iL6bVf272B3qIjp0QqSny6AIm+DkP7oQjkVVLvx9EMhlvd4HJOxPpmtNF/RjA/zz21d7DY/B//saOPpBQa" - .to_string(); + "5-7-i8iL6bVf272B3qIjp0QqSny6AIm+DkP7oQjkVVLvx9EMhlvd4HJOxPpmtNF/RjA/zz21d7DY/B//saOPpBQa"; let shares = vec![share1, share2, share3, share4, share5] .iter() .map(|x| wrap_from_sellibitze(x)) .collect::>(); - let secret = - "The immoral cannot be made moral through the use of secret law.".to_string().into_bytes(); - assert_eq!(recover_secret(shares, false).unwrap(), secret); + let secret = "The immoral cannot be made moral through the use of secret law." + .to_string() + .into_bytes(); + assert_eq!(recover_secret(&shares, false).unwrap(), secret); } #[test] fn test_recover_sellibitze_more_than_threshold_shars() { - let share1 = "2-1-1YAYwmOHqZ69jA".to_string(); - let share2 = "2-4-F7rAjX3UOa53KA".to_string(); - let share3 = "2-2-YJZQDGm22Y77Gw".to_string(); - let share4 = "2-5-j0P4PHsw4lW+rg".to_string(); + let share1 = "2-1-1YAYwmOHqZ69jA"; + let share2 = "2-4-F7rAjX3UOa53KA"; + let share3 = "2-2-YJZQDGm22Y77Gw"; + let share4 = "2-5-j0P4PHsw4lW+rg"; let shares = vec![share1, share2, share3, share4] .iter() @@ -75,5 +75,5 @@ fn test_recover_sellibitze_more_than_threshold_shars() { let mut secret = "My secret".to_string().into_bytes(); secret.push(10); - assert_eq!(recover_secret(shares, false).unwrap(), secret); + assert_eq!(recover_secret(&shares, false).unwrap(), secret); } diff --git a/tests/thss_generation_errors.rs b/tests/thss_generation_errors.rs new file mode 100644 index 0000000..d9b3c5c --- /dev/null +++ b/tests/thss_generation_errors.rs @@ -0,0 +1,14 @@ +#![cfg(feature = "dss")] + +extern crate rusty_secrets; + +use rusty_secrets::dss::thss; + +#[test] +#[should_panic(expected = "ThresholdTooBig")] +fn test_generate_invalid_k() { + let secret = b"These programs were never about terrorism: they're about economic spying, \ + social control, and diplomatic manipulation. They're about power."; + + thss::split_secret(10, 7, secret, &None).unwrap(); +} diff --git a/tests/thss_recovery_errors.rs b/tests/thss_recovery_errors.rs new file mode 100644 index 0000000..4c6c58a --- /dev/null +++ b/tests/thss_recovery_errors.rs @@ -0,0 +1,153 @@ +#![cfg(feature = "dss")] + +extern crate rusty_secrets; + +use rusty_secrets::dss::thss::{recover_secret, Share}; + +#[test] +#[should_panic(expected = "EmptyShares")] +fn test_recover_no_shares() { + let shares = vec![]; + recover_secret(&shares).unwrap(); +} + +#[test] +#[should_panic(expected = "ShareParsingErrorEmptyShare")] +fn test_recover_2_parts_share() { + let share1 = Share { + id: 1, + threshold: 2, + shares_count: 2, + data: "CgmKQZHMO+5n5pU".to_string().into_bytes(), + metadata: None, + }; + let share2 = Share { + id: 2, + threshold: 2, + shares_count: 2, + data: "".to_string().into_bytes(), + metadata: None, + }; + + let shares = vec![share1, share2]; + + recover_secret(&shares).unwrap(); +} + +#[test] +#[should_panic(expected = "ShareParsingInvalidShareId")] +fn test_recover_0_share_num() { + let share1 = Share { + id: 0, + threshold: 2, + shares_count: 2, + data: "1YAYwmOHqZ69jA".to_string().into_bytes(), + metadata: None, + }; + let share2 = Share { + id: 1, + threshold: 2, + shares_count: 2, + data: "YJZQDGm22Y77Gw".to_string().into_bytes(), + metadata: None, + }; + + let shares = vec![share1, share2]; + + recover_secret(&shares).unwrap(); +} + +// --- +// TODO: will be implemented when serialization is done for thss shares +// --- +// #[test] +// #[should_panic(expected = "ShareParsingError")] +// fn test_recover_invalid_b64() { +// let share1 = Share { +// id: 1, +// threshold: 2, +// shares_count: 2, +// data: "1YAYwmOHqZ69jA".to_string().into_bytes(), +// metadata: None +// }; +// let share2 = Share { +// id: 2, +// threshold: 2, +// shares_count: 2, +// data: "YJZQDG((((m22Y)))77Gw".to_string().into_bytes(), +// metadata: None +// }; +// +// let shares = vec![share1, share2]; +// +// recover_secret(&shares).unwrap(); +// } + +#[test] +#[should_panic(expected = "DuplicateShareId")] +fn test_recover_duplicate_shares_number() { + let share1 = Share { + id: 1, + threshold: 2, + shares_count: 2, + data: "1YAYwmOHqZ69jA".to_string().into_bytes(), + metadata: None, + }; + let share2 = Share { + id: 1, + threshold: 2, + shares_count: 2, + data: "YJZQDGm22Y77Gw".to_string().into_bytes(), + metadata: None, + }; + + let shares = vec![share1, share2]; + + recover_secret(&shares).unwrap(); +} + +#[test] +#[should_panic(expected = "DuplicateShareData")] +fn test_recover_duplicate_shares_data() { + let share1 = Share { + id: 1, + threshold: 2, + shares_count: 2, + data: "1YAYwmOHqZ69jA".to_string().into_bytes(), + metadata: None, + }; + let share2 = Share { + id: 2, + threshold: 2, + shares_count: 2, + data: "1YAYwmOHqZ69jA".to_string().into_bytes(), + metadata: None, + }; + + let shares = vec![share1, share2]; + + recover_secret(&shares).unwrap(); +} + +#[test] +#[should_panic(expected = "MissingShares")] +fn test_recover_too_few_shares() { + let share1 = Share { + id: 1, + threshold: 3, + shares_count: 3, + data: "1YAYwmOHqZ69jA".to_string().into_bytes(), + metadata: None, + }; + let share2 = Share { + id: 2, + threshold: 3, + shares_count: 3, + data: "YJZQDGm22Y77Gw".to_string().into_bytes(), + metadata: None, + }; + + let shares = vec![share1, share2]; + + recover_secret(&shares).unwrap(); +}