From fe9d5d0736b587806d2d10a320b2e8216ba827e2 Mon Sep 17 00:00:00 2001 From: Cypher Date: Sun, 24 Dec 2023 15:28:16 +0100 Subject: [PATCH] initial version --- Cargo.lock | 1060 ++++++++++++++++++++++++++++++++++-- Cargo.toml | 63 ++- MAINTAINERS.md | 9 +- MANIFEST.yml | 7 +- README.md | 7 + src/algo/mod.rs | 66 +++ src/algo/ristretto25519.rs | 187 +++++++ src/bindle.rs | 237 ++++++++ src/identity.rs | 119 ++++ src/lib.rs | 40 +- src/main.rs | 169 ++++++ src/proofs.rs | 48 ++ src/seal.rs | 54 ++ src/sigs.rs | 44 ++ 14 files changed, 2026 insertions(+), 84 deletions(-) create mode 100644 src/algo/mod.rs create mode 100644 src/algo/ristretto25519.rs create mode 100644 src/bindle.rs create mode 100644 src/identity.rs create mode 100644 src/main.rs create mode 100644 src/proofs.rs create mode 100644 src/seal.rs create mode 100644 src/sigs.rs diff --git a/Cargo.lock b/Cargo.lock index c655492..1e94076 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,62 +4,348 @@ version = 3 [[package]] name = "amplify" -version = "4.0.0" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26966af46e0d200e8bf2b7f16230997c1c3f2d141bc27ccc091c012ed527b58" +checksum = "8629db306c0bbeb0a402e2918bdcf0026b5ddb24c46460f3bf5410b350d98710" dependencies = [ + "amplify_apfloat", "amplify_derive", "amplify_num", + "amplify_syn", "ascii", "wasm-bindgen", ] +[[package]] +name = "amplify_apfloat" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5b7f29fad2a3def5dfbfed0da85b886eb927a18fe0296c06e39880b7a96db05" +dependencies = [ + "amplify_num", + "bitflags 1.3.2", +] + [[package]] name = "amplify_derive" -version = "3.0.0" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "580f12b79a9e10cfa8d2515128d83a53f387e290096a75904c92b8a2a4d542a6" +checksum = "759dcbfaf94d838367a86d493ec34ccc8aa6fe365cb7880d6bf89006de24d9c1" dependencies = [ "amplify_syn", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "amplify_num" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddce3bc63e807ea02065e8d8b702695f3d302ae4158baddff8b0ce5c73947251" +checksum = "9681187211554ab98f138ba159e90861b136c20afc680dcff2ba82d020721e27" +dependencies = [ + "wasm-bindgen", +] [[package]] name = "amplify_syn" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29b08d74fda406d5a94abfdcdb91ba13bb06562ccf0a4581867fa924ca242b01" +checksum = "7736fb8d473c0d83098b5bac44df6a561e20470375cd8bcae30516dc889fd62a" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", ] +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + [[package]] name = "ascii" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "baid58" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc0585242d87ed976e05db6ae86a0f771f140104a4b6c91b4c3e43b9b2357486" +dependencies = [ + "base58", + "blake3", + "mnemonic", + "sha2", +] + +[[package]] +name = "base58" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581" + +[[package]] +name = "base64" +version = "0.21.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" + +[[package]] +name = "base85" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36915bbaca237c626689b5bd14d02f2ba7a5a359d30a2a08be697392e3718079" +dependencies = [ + "thiserror", +] + +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + +[[package]] +name = "bitcoin-internals" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" + +[[package]] +name = "bitcoin_hashes" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" +dependencies = [ + "bitcoin-internals", + "hex-conservative", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + +[[package]] +name = "blake3" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0231f06152bf547e9c2b5194f247cd97aacf6dcd8b15d8e5ec0663f64580da87" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bp-consensus" +version = "0.11.0-beta.2" +source = "git+https://github.com/BP-WG/bp-core?branch=doubleanchors#d3a57c213f34d9012101b9969cdc8b0d60a6fe60" +dependencies = [ + "amplify", + "chrono", + "commit_verify", + "secp256k1", + "strict_encoding", +] + +[[package]] +name = "bp-core" +version = "0.11.0-beta.1" +source = "git+https://github.com/BP-WG/bp-core?branch=doubleanchors#d3a57c213f34d9012101b9969cdc8b0d60a6fe60" +dependencies = [ + "amplify", + "bp-consensus", + "bp-dbc", + "bp-seals", + "commit_verify", + "single_use_seals", + "strict_encoding", +] + +[[package]] +name = "bp-dbc" +version = "0.11.0-beta.1" +source = "git+https://github.com/BP-WG/bp-core?branch=doubleanchors#d3a57c213f34d9012101b9969cdc8b0d60a6fe60" +dependencies = [ + "amplify", + "base85", + "bp-consensus", + "commit_verify", + "secp256k1", + "strict_encoding", +] + +[[package]] +name = "bp-derive" +version = "0.11.0-beta.2" +source = "git+https://github.com/BP-WG/bp-std?branch=v0.11#49fea91b28767859931ddc393aa02d7c9d010ff0" +dependencies = [ + "amplify", + "bitcoin_hashes", + "bp-consensus", + "bp-invoice", + "commit_verify", + "indexmap", +] + +[[package]] +name = "bp-invoice" +version = "0.11.0-beta.2" +source = "git+https://github.com/BP-WG/bp-std?branch=v0.11#49fea91b28767859931ddc393aa02d7c9d010ff0" +dependencies = [ + "amplify", + "bech32", + "bitcoin_hashes", + "bp-consensus", +] + +[[package]] +name = "bp-seals" +version = "0.11.0-beta.1" +source = "git+https://github.com/BP-WG/bp-core?branch=doubleanchors#d3a57c213f34d9012101b9969cdc8b0d60a6fe60" +dependencies = [ + "amplify", + "baid58", + "bp-consensus", + "bp-dbc", + "commit_verify", + "rand", + "single_use_seals", + "strict_encoding", +] + +[[package]] +name = "bp-std" +version = "0.11.0-beta.2" +source = "git+https://github.com/BP-WG/bp-std?branch=v0.11#49fea91b28767859931ddc393aa02d7c9d010ff0" +dependencies = [ + "amplify", + "bp-consensus", + "bp-core", + "bp-derive", + "bp-invoice", + "descriptors", + "psbt", +] + [[package]] name = "bumpalo" -version = "3.12.1" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b1ce199063694f33ffb7dd4e0ee620741495c32833cde5aa08f02a0bf96f0c8" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.0.79" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] [[package]] name = "cfg-if" @@ -67,12 +353,176 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-targets 0.48.5", +] + +[[package]] +name = "clap" +version = "4.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", + "terminal_size", +] + +[[package]] +name = "clap_derive" +version = "4.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.42", +] + +[[package]] +name = "clap_lex" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "commit_encoding_derive" +version = "0.10.0" +source = "git+https://github.com/LNP-BP/client_side_validation?branch=v0.11#6b634bccd96d2cb857a44ae48417f8e35ecb3de7" +dependencies = [ + "amplify", + "amplify_syn", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "commit_verify" +version = "0.11.0-beta.1" +source = "git+https://github.com/LNP-BP/client_side_validation?branch=v0.11#6b634bccd96d2cb857a44ae48417f8e35ecb3de7" +dependencies = [ + "amplify", + "commit_encoding_derive", + "rand", + "ripemd", + "sha2", + "strict_encoding", +] + +[[package]] +name = "constant_time_eq" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "cpufeatures" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +dependencies = [ + "libc", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "ct-codecs" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3b7eb4404b8195a9abb6356f4ac07d8ba267045c8d6d220ac4dc992e6cc75df" +[[package]] +name = "descriptors" +version = "0.11.0-beta.2" +source = "git+https://github.com/BP-WG/bp-std?branch=v0.11#49fea91b28767859931ddc393aa02d7c9d010ff0" +dependencies = [ + "amplify", + "bp-derive", + "indexmap", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + [[package]] name = "ec25519" version = "0.1.0" @@ -83,83 +533,399 @@ dependencies = [ "getrandom", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ "cfg-if", "libc", "wasi", ] +[[package]] +name = "half" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b4af3693f1b705df946e9fe5631932443781d0aabb423b62fcd4d73f6d2fd0" +dependencies = [ + "crunchy", +] + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hex-conservative" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2" + +[[package]] +name = "iana-time-zone" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "js-sys" +version = "0.3.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + [[package]] name = "libc" -version = "0.2.142" +version = "0.2.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" + +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.1", + "libc", + "redox_syscall", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" [[package]] name = "log" -version = "0.4.17" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "mnemonic" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +checksum = "29fae0e4c0b155d3b019a7cbc27abe4a90e15c06814d27889ce9f5f44e2faf77" dependencies = [ - "cfg-if", + "byteorder", + "lazy_static", +] + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", ] [[package]] name = "once_cell" -version = "1.17.1" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.56" +version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" +checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8" dependencies = [ "unicode-ident", ] +[[package]] +name = "psbt" +version = "0.11.0-beta.2" +source = "git+https://github.com/BP-WG/bp-std?branch=v0.11#49fea91b28767859931ddc393aa02d7c9d010ff0" +dependencies = [ + "amplify", + "base64", + "bp-core", + "bp-derive", + "chrono", + "commit_verify", + "descriptors", + "indexmap", + "strict_encoding", +] + [[package]] name = "quote" -version = "1.0.26" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_users" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest", +] + +[[package]] +name = "rustix" +version = "0.38.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" +dependencies = [ + "bitflags 2.4.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + [[package]] name = "secp256k1" -version = "0.27.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" +checksum = "2acea373acb8c21ecb5a23741452acd2593ed44ee3d343e72baaa143bc89d0d5" dependencies = [ + "rand", "secp256k1-sys", ] [[package]] name = "secp256k1-sys" -version = "0.8.1" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" +checksum = "4dd97a086ec737e30053fd5c46f097465d25bb81dd3608825f65298c4c98be83" dependencies = [ "cc", ] [[package]] -name = "ssi" +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shellexpand" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da03fa3b94cc19e3ebfc88c4229c49d8f08cdbd1228870a45f0ffdf84988e14b" +dependencies = [ + "dirs", +] + +[[package]] +name = "single_use_seals" +version = "0.11.0-beta.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a46b0f289450dc06e7b94f048a55ac437177532f2c6c9bed12c1de7ac948f5a5" +dependencies = [ + "amplify_derive", +] + +[[package]] +name = "ssid" version = "0.1.0" dependencies = [ "amplify", + "baid58", + "base85", + "bp-std", + "clap", + "commit_verify", "ec25519", - "secp256k1", + "rand", + "shellexpand", + "strict_encoding", + "strict_types", +] + +[[package]] +name = "strict_encoding" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab7b75b4af0aff9dd97b68df262bf0e807b7d007cc860fa217943f898a05a5ab" +dependencies = [ + "amplify", + "half", + "strict_encoding_derive", +] + +[[package]] +name = "strict_encoding_derive" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37064ec285e2a633465eb525c8698eea51373dee889fe310e0d32df8343e7f4f" +dependencies = [ + "amplify_syn", + "heck", + "proc-macro2", + "quote", + "syn 1.0.109", ] +[[package]] +name = "strict_types" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d10cc45e67d452cfe0d87d4714c3250190d97479af3502bbd823651bfe0f505f" +dependencies = [ + "amplify", + "baid58", + "half", + "indexmap", + "sha2", + "strict_encoding", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "syn" version = "1.0.109" @@ -171,11 +937,70 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "2.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b7d0a2c048d661a1a59fcd7355baa232f7ed34e0ee4df2eef3c1c1c0d3852d8" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "terminal_size" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" +dependencies = [ + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "thiserror" +version = "1.0.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.42", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "utf8parse" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasi" @@ -185,9 +1010,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.84" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -195,24 +1020,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.84" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.42", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.84" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -220,19 +1045,160 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.84" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.42", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.84" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" + +[[package]] +name = "windows-core" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" diff --git a/Cargo.toml b/Cargo.toml index 839523a..37f5fdf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,45 +1,50 @@ -[workspace] -default-members = [ - "." -] - -[workspace.package] -authors = ["Dr. Maxim Orlovsky "] -homepage = "https://cyphernet.io" -repository = "https://github.com/Cyphernet-DAO/ssi" -rust-version = "1.66" -edition = "2021" -license = "Apache-2.0" - -[workspace.dependencies] -amplify = "4.0.0" - -### -### Main package (`ssi`) -### - [package] -name = "ssi" +name = "ssid" version = "0.1.0" description = "Self-sovereign identity" keywords = ["privacy", "cypherpunk", "identity"] categories = ["cryptography"] readme = "README.md" -authors = { workspace = true } -homepage = { workspace = true } -repository = { workspace = true } -rust-version = { workspace = true } -edition = { workspace = true } -license = { workspace = true } +authors = ["Cypher "] +homepage = "https://cyphernet.io" +repository = "https://github.com/Cyphernet-DAO/ssid" +rust-version = "1.66" +edition = "2021" +license = "Apache-2.0" + +[lib] + +[[bin]] +name = "ssid" +required-features = ["cli"] [dependencies] -amplify = { workspace = true } +amplify = "4.5.0" +commit_verify = "0.11.0-beta.1" +strict_encoding = "2.6.1" +strict_types = "1.6.3" ec25519 = "0.1.0" -secp256k1 = { version = "0.27.0", optional = true } +baid58 = "0.4.4" +base85 = "2.0.0" +bp-std = { version = "0.11.0-beta.2", features = ["client-side-validation"] } +rand = "0.8.5" +clap = { version = "4.4.11", features = ["derive", "env", "wrap_help"], optional = true } +shellexpand = { version = "3.1.0", optional = true } [features] default = [] +all = ["cli"] +cli = ["clap", "shellexpand"] [package.metadata.docs.rs] all-features = true rustc-args = ["--cfg", "docsrs"] + +[patch.crates-io] +commit_verify = { git = "https://github.com/LNP-BP/client_side_validation", branch = "v0.11" } +bp-consensus = { git = "https://github.com/BP-WG/bp-core", branch = "doubleanchors" } +bp-dbc = { git = "https://github.com/BP-WG/bp-core", branch = "doubleanchors" } +bp-seals = { git = "https://github.com/BP-WG/bp-core", branch = "doubleanchors" } +bp-core = { git = "https://github.com/BP-WG/bp-core", branch = "doubleanchors" } +psbt = { git = "https://github.com/BP-WG/bp-std", branch = "v0.11" } +bp-std = { git = "https://github.com/BP-WG/bp-std", branch = "v0.11" } diff --git a/MAINTAINERS.md b/MAINTAINERS.md index a3af1e0..754ca1f 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -1,6 +1,11 @@ -Maxim Orlovsky +Cypher +--------------- +- GPG: `54DD1B1181EC60253A9357956482D826A6BEA6F9` +- EMail: [cypher@cyphernet.io](mailto:cypher@cyphernet.io) + +- Maxim Orlovsky --------------- - GitHub: [@dr-orlovsky](https://github.com/dr-orlovsky) - GPG: `EAE730CEC0C663763F028A5860094BAF18A26EC9` - SSH: `BoSGFzbyOKC7Jm28MJElFboGepihCpHop60nS8OoG/A` -- EMail: [dr@orlovsky.ch](mailto:dr@orlovsky.ch) +- EMail: [orlovsky@cyphernet.io](mailto:orlovsky@cyphernet.io) diff --git a/MANIFEST.yml b/MANIFEST.yml index 59f06da..d5f37ec 100644 --- a/MANIFEST.yml +++ b/MANIFEST.yml @@ -4,11 +4,14 @@ Kind: Free software License: Apache-2.0 Language: Rust Compiler: 1.66 -Author: Maxim Orlovsky +Author: Cypher Maintained: Cyphernet DAO, Switzerland Maintainers: + Cypher: + GPG: 54DD1B1181EC60253A9357956482D826A6BEA6F9 + EMail: cypher@cyphernet.io Maxim Orlovsky: GitHub: @dr-orlovsky GPG: EAE730CEC0C663763F028A5860094BAF18A26EC9 SSH: BoSGFzbyOKC7Jm28MJElFboGepihCpHop60nS8OoG/A - EMail: dr@orlovsky.ch + EMail: orlovsky@cyphernet.io diff --git a/README.md b/README.md index 60a8396..c398d3e 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,9 @@ # Self-sovereign identity suite +Self-sovereign identity is an identity format developed by Cyphernet +Association, Switzerland. Being similar to OpenPGP, it operates without +any key servers, using blockchain infrastructure. This allows provable and +globally enforceable key revocation without dedicated revocation keys, +global propagation of new keys information and provable or unique +signatures which are timestamped or created using single-use-seal +mechanism. diff --git a/src/algo/mod.rs b/src/algo/mod.rs new file mode 100644 index 0000000..b5d63d8 --- /dev/null +++ b/src/algo/mod.rs @@ -0,0 +1,66 @@ +// Self-sovereign identity (SSID) +// +// SPDX-License-Identifier: Apache-2.0 +// +// Written in 2023-204 by +// Cypher +// +// Copyright 2023-2024 Cyphernet DAO, Switzerland +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +mod ristretto25519; + +use std::fmt::{Debug, Display}; +use std::str::FromStr; + +use amplify::Bytes4; +use baid58::Baid58ParseError; +pub use ristretto25519::{RistrettoPk, RistrettoSig, RistrettoSk}; +use strict_encoding::{StrictDecode, StrictDumb, StrictEncode, StrictType}; + +use crate::{BindleContent, Digest}; + +pub type Fingerprint = Bytes4; + +pub trait Sk: BindleContent { + type Sig: Sig; + + fn generate() -> Self; + + fn sign(&self, message: impl Into) -> Self::Sig; +} + +pub trait Pk: + Copy + + Eq + + Debug + + Display + + FromStr + + StrictType + + StrictDumb + + StrictEncode + + StrictDecode +{ + type Sk: Sk; + const ID: u8; + + fn with(sk: &Self::Sk) -> Self; + + #[must_use] + fn verify(&self, message: impl Into, sig: &::Sig) -> bool; + + fn fingerprint(&self) -> Fingerprint; +} + +pub trait Sig: Copy + Eq + Debug + StrictType + StrictDumb + StrictEncode + StrictDecode {} diff --git a/src/algo/ristretto25519.rs b/src/algo/ristretto25519.rs new file mode 100644 index 0000000..ada43ca --- /dev/null +++ b/src/algo/ristretto25519.rs @@ -0,0 +1,187 @@ +// Self-sovereign identity (SSID) +// +// SPDX-License-Identifier: Apache-2.0 +// +// Written in 2023-204 by +// Cypher +// +// Copyright 2023-2024 Cyphernet DAO, Switzerland +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::io; +use std::ops::Deref; +use std::str::FromStr; + +use baid58::{Baid58ParseError, Chunking, FromBaid58, ToBaid58, CHUNKING_32}; +use ec25519::{Noise, PublicKey, SecretKey, Signature}; +use rand::{random, thread_rng, Rng}; +use strict_encoding::{ + DecodeError, ReadTuple, StrictDecode, StrictDeserialize, StrictDumb, StrictEncode, + StrictProduct, StrictSerialize, StrictTuple, StrictType, TypedRead, TypedWrite, +}; + +use super::{Fingerprint, Pk, Sig}; +use crate::{BindleContent, Digest, Sk, LIB_NAME_SSID}; + +pub struct RistrettoSk(SecretKey); + +impl StrictType for RistrettoSk { + const STRICT_LIB_NAME: &'static str = LIB_NAME_SSID; +} +impl StrictProduct for RistrettoSk {} +impl StrictTuple for RistrettoSk { + const FIELD_COUNT: u8 = 1; +} +impl StrictEncode for RistrettoSk { + fn strict_encode(&self, writer: W) -> io::Result { + writer.write_newtype::(self.0.deref()) + } +} +impl StrictDecode for RistrettoSk { + fn strict_decode(reader: &mut impl TypedRead) -> Result { + reader.read_tuple(|r| { + let data = r.read_field()?; + Ok(Self(SecretKey::new(data))) + }) + } +} +impl StrictDumb for RistrettoSk { + fn strict_dumb() -> Self { Self(SecretKey::new([0xFAu8; 64])) } +} +impl StrictSerialize for RistrettoSk {} +impl StrictDeserialize for RistrettoSk {} + +impl Sk for RistrettoSk { + type Sig = RistrettoSig; + + fn generate() -> Self { + let mut data = [0u8; 64]; + thread_rng().fill(&mut data); + Self(SecretKey::new(data)) + } + + fn sign(&self, message: impl Into) -> Self::Sig { + RistrettoSig(self.0.sign(message.into(), Some(Noise::new(random())))) + } +} + +impl BindleContent for RistrettoSk { + const MAGIC: [u8; 4] = *b"SSSK"; + const PLATE_TITLE: &'static str = "SSID SECRET KEY"; + type Id = RistrettoPk; + + fn bindle_id(&self) -> Self::Id { RistrettoPk::with(self) } +} + +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display)] +#[display(Self::to_baid58_string)] +pub struct RistrettoPk(PublicKey); + +impl From<[u8; 33]> for RistrettoPk { + fn from(value: [u8; 33]) -> Self { + assert_eq!(value[0], Self::ID, "invalid key type"); + let mut data = [0u8; 32]; + data.copy_from_slice(&value[1..]); + Self(PublicKey::new(data)) + } +} + +impl ToBaid58<33> for RistrettoPk { + const HRI: &'static str = "ssi"; + const CHUNKING: Option = CHUNKING_32; + fn to_baid58_payload(&self) -> [u8; 33] { + let mut payload = [0u8; 33]; + payload[0] = Self::ID; + payload[1..].copy_from_slice(self.0.deref()); + payload + } + fn to_baid58_string(&self) -> String { self.to_string() } +} +impl FromBaid58<33> for RistrettoPk {} +impl FromStr for RistrettoPk { + type Err = Baid58ParseError; + fn from_str(s: &str) -> Result { Self::from_baid58_chunked_str(s, ':', '#') } +} +impl RistrettoPk { + pub fn to_baid58_string(&self) -> String { format!("{::<#.2}", self.to_baid58()) } + pub fn to_mnemonic(&self) -> String { self.to_baid58().mnemonic() } +} + +impl Pk for RistrettoPk { + type Sk = RistrettoSk; + const ID: u8 = 1; + + fn with(sk: &Self::Sk) -> Self { Self(sk.0.public_key()) } + + fn verify(&self, message: impl Into, sig: &::Sig) -> bool { + self.0.verify(message.into(), &sig.0).is_ok() + } + + fn fingerprint(&self) -> Fingerprint { + Fingerprint::copy_from_slice(&self.0[0..4]).expect("fixed length") + } +} + +impl StrictType for RistrettoPk { + const STRICT_LIB_NAME: &'static str = LIB_NAME_SSID; +} +impl StrictProduct for RistrettoPk {} +impl StrictTuple for RistrettoPk { + const FIELD_COUNT: u8 = 1; +} +impl StrictEncode for RistrettoPk { + fn strict_encode(&self, writer: W) -> io::Result { + writer.write_newtype::(self.0.deref()) + } +} +impl StrictDecode for RistrettoPk { + fn strict_decode(reader: &mut impl TypedRead) -> Result { + reader.read_tuple(|r| { + let data = r.read_field()?; + Ok(Self(PublicKey::new(data))) + }) + } +} +impl StrictDumb for RistrettoPk { + fn strict_dumb() -> Self { Self(PublicKey::new([0xFAu8; 32])) } +} + +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +pub struct RistrettoSig(Signature); + +impl Sig for RistrettoSig {} + +impl StrictType for RistrettoSig { + const STRICT_LIB_NAME: &'static str = LIB_NAME_SSID; +} +impl StrictProduct for RistrettoSig {} +impl StrictTuple for RistrettoSig { + const FIELD_COUNT: u8 = 1; +} +impl StrictEncode for RistrettoSig { + fn strict_encode(&self, writer: W) -> io::Result { + writer.write_newtype::(self.0.deref()) + } +} +impl StrictDecode for RistrettoSig { + fn strict_decode(reader: &mut impl TypedRead) -> Result { + reader.read_tuple(|r| { + let data = r.read_field()?; + Ok(Self(Signature::new(data))) + }) + } +} +impl StrictDumb for RistrettoSig { + fn strict_dumb() -> Self { Self(Signature::new([0xFAu8; 64])) } +} diff --git a/src/bindle.rs b/src/bindle.rs new file mode 100644 index 0000000..17c3e0e --- /dev/null +++ b/src/bindle.rs @@ -0,0 +1,237 @@ +// Self-sovereign identity (SSID) +// +// SPDX-License-Identifier: Apache-2.0 +// +// Written in 2023-204 by +// Cypher +// +// Copyright 2023-2024 Cyphernet DAO, Switzerland +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Bindle is a wrapper for ASCII armoring binary data containers, which can be serialized +//! and optionally signed by the creator with certain id and send over to a +//! remote party. + +use std::collections::BTreeMap; +use std::fmt::{Debug, Display}; +use std::io::{Read, Write}; +use std::ops::Deref; +use std::path::Path; +use std::str::FromStr; +use std::{fs, io}; + +use amplify::confinement; +use amplify::confinement::{Confined, TinyVec, U24}; +use baid58::Baid58ParseError; +use strict_encoding::{ + DecodeError, StrictDecode, StrictDeserialize, StrictDumb, StrictEncode, StrictReader, + StrictSerialize, StrictType, StrictWriter, STRICT_TYPES_LIB, +}; + +use crate::{Pk, RistrettoPk, SigCert}; + +pub trait BindleContent: StrictSerialize + StrictDeserialize + StrictDumb { + /// Magic bytes used in saving/restoring container from a file. + const MAGIC: [u8; 4]; + /// String used in ASCII armored blocks + const PLATE_TITLE: &'static str; + + type Id: Copy + + Eq + + Debug + + Display + + FromStr + + StrictType + + StrictDumb + + StrictEncode + + StrictDecode; + + fn bindle_id(&self) -> Self::Id; + fn bindle_headers(&self) -> BTreeMap<&'static str, String> { none!() } + fn bindle(self) -> Bindle { Bindle::new(self) } + fn bindle_mnemonic(&self) -> Option { None } +} + +#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] +#[strict_type(lib = STRICT_TYPES_LIB)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", rename_all = "camelCase") +)] +pub struct Bindle { + id: C::Id, + data: C, + sigs: TinyVec>, +} + +impl Deref for Bindle { + type Target = C; + fn deref(&self) -> &Self::Target { &self.data } +} + +impl From for Bindle { + fn from(data: C) -> Self { Bindle::new(data) } +} + +impl Bindle { + pub fn new(data: C) -> Self { + Bindle { + id: data.bindle_id(), + data, + sigs: empty!(), + } + } + + pub fn id(&self) -> C::Id { self.id } + + pub fn into_split(self) -> (C, TinyVec>) { (self.data, self.sigs) } + pub fn unbindle(self) -> C { self.data } +} + +#[derive(Clone, PartialEq, Eq, Debug, Display, Error, From)] +#[display(doc_comments)] +pub enum BindleParseError { + /// the provided text doesn't represent a recognizable ASCII-armored RGB + /// bindle encoding. + WrongStructure, + + /// Id header of the bindle contains unparsable information. Details: {0} + InvalidId(Baid58ParseError), + + /// the actual data doesn't match the provided id. + /// + /// Actual id: {actual}. + /// + /// Expected id: {expected}. + MismatchedId { actual: Id, expected: Id }, + + /// bindle data has invalid Base85 encoding (ASCII armoring). + #[from(base85::Error)] + Base85, + + /// unable to decode the provided bindle data. Details: {0} + #[from] + Deserialize(strict_encoding::DeserializeError), + + /// bindle contains more than 16MB of data. + #[from(confinement::Error)] + TooLarge, +} + +impl FromStr for Bindle { + type Err = BindleParseError; + + fn from_str(s: &str) -> Result { + let mut lines = s.lines(); + let first = format!("-----BEGIN {}-----", C::PLATE_TITLE); + let last = format!("-----END {}-----", C::PLATE_TITLE); + if (lines.next(), lines.next_back()) != (Some(&first), Some(&last)) { + return Err(BindleParseError::WrongStructure); + } + let mut header_id = None; + for line in lines.by_ref() { + if line.is_empty() { + break; + } + if let Some(id_str) = line.strip_prefix("Id: ") { + header_id = Some(C::Id::from_str(id_str).map_err(BindleParseError::InvalidId)?); + } + } + let armor = lines.filter(|l| !l.is_empty()).collect::(); + let data = base85::decode(&armor)?; + let data = C::from_strict_serialized::(Confined::try_from(data)?)?; + let id = data.bindle_id(); + if let Some(header_id) = header_id { + if header_id != id { + return Err(BindleParseError::MismatchedId { + actual: id, + expected: header_id, + }); + } + } + // TODO: check mnemonic + // TODO: parse and validate sigs + Ok(Self { + id, + data, + sigs: none!(), + }) + } +} + +impl Display for Bindle { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + writeln!(f, "-----BEGIN {}-----", C::PLATE_TITLE)?; + writeln!(f, "Id: {:-#}", self.id)?; + if let Some(mnemonic) = self.bindle_mnemonic() { + writeln!(f, "Mnemonic: {}", mnemonic)?; + } + for (header, value) in self.bindle_headers() { + writeln!(f, "{header}: {value}")?; + } + for cert in &self.sigs { + writeln!(f, "Signed-By: {}", cert.identity())?; + } + writeln!(f)?; + + // TODO: Replace with streamed writer + let data = self.data.to_strict_serialized::().expect("in-memory"); + let data = base85::encode(&data); + let mut data = data.as_str(); + while data.len() >= 64 { + let (line, rest) = data.split_at(64); + writeln!(f, "{}", line)?; + data = rest; + } + writeln!(f, "{}", data)?; + + writeln!(f, "\n-----END {}-----", C::PLATE_TITLE)?; + Ok(()) + } +} + +#[derive(Clone, Eq, PartialEq, Debug, Display, Error, From)] +#[display(doc_comments)] +pub enum LoadError { + /// invalid file data. + InvalidMagic, + + #[display(inner)] + #[from] + #[from(io::Error)] + Decode(DecodeError), +} + +impl Bindle { + pub fn load(path: impl AsRef) -> Result { + let mut magic = [0u8; 4]; + let mut file = fs::File::open(path)?; + file.read_exact(&mut magic)?; + if magic != C::MAGIC { + return Err(LoadError::InvalidMagic); + } + let mut reader = StrictReader::with(usize::MAX, file); + let me = Self::strict_decode(&mut reader)?; + Ok(me) + } + + pub fn save(&self, path: impl AsRef) -> Result<(), io::Error> { + let mut file = fs::File::create(path)?; + file.write_all(&C::MAGIC)?; + let writer = StrictWriter::with(usize::MAX, file); + self.strict_encode(writer)?; + Ok(()) + } +} diff --git a/src/identity.rs b/src/identity.rs new file mode 100644 index 0000000..1d102a3 --- /dev/null +++ b/src/identity.rs @@ -0,0 +1,119 @@ +// Self-sovereign identity (SSID) +// +// SPDX-License-Identifier: Apache-2.0 +// +// Written in 2023-204 by +// Cypher +// +// Copyright 2023-2024 Cyphernet DAO, Switzerland +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use amplify::confinement::{SmallVec, U8}; +use commit_verify::{Digest as _, Sha256}; +use strict_encoding::{StrictDeserialize, StrictSerialize}; + +use crate::{BindleContent, Digest, Fingerprint, Pk, Proof, RistrettoPk, Seal, Sk, LIB_NAME_SSID}; + +pub struct Ssi { + pub sk: K::Sk, + pub cert: IdCert, +} + +impl Ssi { + pub fn new(seal: Seal) -> Self { + let sk = K::Sk::generate(); + let identity = Identity { + key: K::with(&sk), + seal, + }; + let sig = sk.sign(identity); + Ssi { + sk, + cert: IdCert::new(identity, sig), + } + } + + pub fn fingerprint(&self) -> Fingerprint { self.cert.fingerprint() } +} + +/// Has binary form included into the blockchain (witness in case of bitcoin) +#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] +#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_SSID)] +#[display("ssi:{key}", alt = "ssi:{key}@{seal}")] +pub struct Identity { + pub key: K, + pub seal: Seal, +} + +impl StrictSerialize for Identity {} + +impl Identity { + pub fn fingerprint(&self) -> Fingerprint { self.key.fingerprint() } +} + +impl From> for Digest { + fn from(identity: Identity) -> Self { + let data = identity + .to_strict_serialized::() + .expect("serialized identity does not fit 256 bytes"); + let mut hasher = Sha256::new(); + hasher.update(data); + <[u8; 32]>::from(hasher.finalize()).into() + } +} + +#[derive(Clone, Eq, PartialEq, Debug)] +#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_SSID)] +pub struct Revocation { + pub new_identity: Identity, + pub revocation_proof: Proof, +} + +#[derive(Clone, Eq, PartialEq, Debug)] +#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_SSID)] +pub struct IdCert { + pub revocations: SmallVec>, + pub genesis_id: Identity, + pub genesis_sig: ::Sig, +} + +impl StrictSerialize for IdCert {} +impl StrictDeserialize for IdCert {} + +impl IdCert { + pub fn new(identity: Identity, sig: ::Sig) -> Self { + Self { + revocations: none!(), + genesis_id: identity, + genesis_sig: sig, + } + } + + pub fn identity(&self) -> Identity { + self.revocations.last().map(|r| r.new_identity).unwrap_or(self.genesis_id) + } + + pub fn fingerprint(&self) -> Fingerprint { self.identity().fingerprint() } +} + +impl BindleContent for IdCert { + const MAGIC: [u8; 4] = *b"SSID"; + const PLATE_TITLE: &'static str = "SSID IDENTITY CERTIFICATE"; + type Id = K; + + fn bindle_id(&self) -> Self::Id { self.identity().key } +} diff --git a/src/lib.rs b/src/lib.rs index 1a06993..5ec076b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,11 +1,11 @@ -// Self-sovereign identity (SSI) +// Self-sovereign identity (SSID) // // SPDX-License-Identifier: Apache-2.0 // -// Written in 2023 by -// Dr. Maxim Orlovsky +// Written in 2023-204 by +// Cypher // -// Copyright 2023 Cyphernet DAO, Switzerland +// Copyright 2023-2024 Cyphernet DAO, Switzerland // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -21,3 +21,35 @@ #![cfg_attr(docsrs, feature(doc_auto_cfg))] +/// # URLs +/// +/// - `ssid:`, chunked +/// +/// # Armors +/// +/// Base85 armor in "bindle" format. +/// +/// Used for IdCert and SigCert + +#[macro_use] +extern crate amplify; +#[macro_use] +extern crate strict_encoding; + +mod algo; +mod identity; +mod sigs; +mod bindle; +mod proofs; +mod seal; + +pub use crate::algo::{Fingerprint, Pk, RistrettoPk, RistrettoSig, RistrettoSk, Sig, Sk}; +pub use crate::bindle::{Bindle, BindleContent, BindleParseError, LoadError}; +pub use crate::identity::{IdCert, Identity, Revocation, Ssi}; +pub use crate::proofs::{BpProof, Proof}; +pub use crate::seal::Seal; +pub use crate::sigs::{SigCert, Signature}; + +pub const LIB_NAME_SSID: &str = "SSID"; + +pub type Digest = amplify::Bytes32; diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..2f49437 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,169 @@ +// Self-sovereign identity (SSID) +// +// SPDX-License-Identifier: Apache-2.0 +// +// Written in 2023-204 by +// Cypher +// +// Copyright 2023-2024 Cyphernet DAO, Switzerland +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[macro_use] +extern crate amplify; +#[macro_use] +extern crate clap; + +use std::path::PathBuf; +use std::str::FromStr; +use std::{fs, io}; + +use bpstd::Address; +use clap::{Parser, ValueHint}; +use ssid::{BindleContent, Fingerprint, RistrettoPk, Seal, Ssi}; + +pub const DATA_DIR_ENV: &str = "SSID_DATA_DIR"; +#[cfg(any(target_os = "linux"))] +pub const DATA_DIR: &str = "~/.ssid"; +#[cfg(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))] +pub const DATA_DIR: &str = "~/.ssid"; +#[cfg(target_os = "macos")] +pub const DATA_DIR: &str = "~/Library/Application Support/SSID"; +#[cfg(target_os = "windows")] +pub const DATA_DIR: &str = "~\\AppData\\Local\\SSID"; +#[cfg(target_os = "ios")] +pub const DATA_DIR: &str = "~/Documents"; +#[cfg(target_os = "android")] +pub const DATA_DIR: &str = "."; + +pub const DEFAULT_ESPLORA: &str = "https://blockstream.info/testnet/api"; + +#[derive(Parser, Clone, Eq, PartialEq, Debug)] +#[command(author, version, about = "Self-sovereign identity command-line tool", long_about = Some("Suite for working with self-sovereign identity. + +Self-sovereign identity is an identity format developed by Cyphernet +Association, Switzerland. Being similar to OpenPGP, it operates without +any key servers, using blockchain infrastructure. This allows provable and +globally enforceable key revocation without dedicated revocation keys, +global propagation of new keys information and provable or unique +signatures which are timestamped or created using single-use-seal +mechanism."))] +pub struct Cli { + /// Produce verbose output + #[arg(short, long, action = clap::ArgAction::Count)] + verbose: u8, + + /// Data directory path. + /// + /// Path to the directory that contains RGB stored data. + #[arg( + short, + long, + global = true, + default_value = DATA_DIR, + env = DATA_DIR_ENV, + value_hint = ValueHint::DirPath + )] + pub data_dir: PathBuf, + + #[command(subcommand)] + command: Command, +} + +impl Cli { + pub fn process(&mut self) -> Result<(), io::Error> { + self.data_dir = + PathBuf::from(shellexpand::tilde(&self.data_dir.display().to_string()).to_string()); + fs::create_dir_all(&self.data_dir) + } +} + +#[derive(Subcommand, Clone, Eq, PartialEq, Debug)] +pub enum Command { + /// Generate new identity + Generate { + /// Single-use-seal definition which should be used for revocation + seal: Seal, + }, + + /// Revoke existing key + Revoke { + /// Identity which key should be revoked + identity: IdArg, + + // /// Output descriptor for the seal which is closed + // descriptor: StdDescr, + /// Address to pay the remaining funds + address: Address, + + /// File to save generated PSBT used for the revocation + #[clap(value_hint = ValueHint::DirPath)] + psbt: Option, + }, + + /// List known identities + List {}, + + /// Add an identity to an address book + Add {}, + + /// Export public information about identity + Export {}, + + /// Sign using identity + Sign {}, + + /// Verify signature + Verify {}, + + /// Encrypt for a given identities + Encrypt {}, + + /// Decrypt previously encrypted data + Decrypt {}, +} + +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Display, From)] +#[display(inner)] +pub enum IdArg { + #[from] + Fingerprint(Fingerprint), +} + +impl FromStr for IdArg { + type Err = amplify::hex::Error; + + fn from_str(s: &str) -> Result { + Fingerprint::from_str(s).map(Self::Fingerprint) + } +} + +fn main() -> Result<(), io::Error> { + let mut cli = Cli::parse(); + cli.process()?; + + match cli.command { + Command::Generate { seal } => { + let ssi = Ssi::::new(seal); + let fp = ssi.fingerprint(); + let (mut sk_file, mut pk_file) = (cli.data_dir.clone(), cli.data_dir.clone()); + sk_file.push(format!("{fp}")); + pk_file.push(format!("{fp}_pub")); + fs::write(sk_file, &ssi.sk.bindle().to_string())?; + fs::write(pk_file, &ssi.cert.bindle().to_string())?; + } + _ => todo!(), + } + + Ok(()) +} diff --git a/src/proofs.rs b/src/proofs.rs new file mode 100644 index 0000000..68531b5 --- /dev/null +++ b/src/proofs.rs @@ -0,0 +1,48 @@ +// Self-sovereign identity (SSID) +// +// SPDX-License-Identifier: Apache-2.0 +// +// Written in 2023-204 by +// Cypher +// +// Copyright 2023-2024 Cyphernet DAO, Switzerland +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use amplify::confinement::LargeVec; +use amplify::Bytes32; +use bpstd::{Tx, UnsignedTx}; + +use crate::LIB_NAME_SSID; + +// TODO: Move to BP Seals +#[derive(Clone, Eq, PartialEq, Debug)] +#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_SSID, tags = custom, dumb = Self::Bitcoin(strict_dumb!()))] +pub enum Proof { + #[strict_type(tag = 0x00)] + Bitcoin(BpProof), + + #[strict_type(tag = 0x01)] + Liquid(BpProof), +} + +// TODO: Move to BP Seals +#[derive(Clone, Eq, PartialEq, Debug)] +#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_SSID)] +pub struct BpProof { + pub seal_tx: UnsignedTx, + pub witness_tx: Tx, + pub merkle_path: LargeVec, +} diff --git a/src/seal.rs b/src/seal.rs new file mode 100644 index 0000000..c23de2c --- /dev/null +++ b/src/seal.rs @@ -0,0 +1,54 @@ +// Self-sovereign identity (SSID) +// +// SPDX-License-Identifier: Apache-2.0 +// +// Written in 2023-204 by +// Cypher +// +// Copyright 2023-2024 Cyphernet DAO, Switzerland +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::str::FromStr; + +use bpstd::{Outpoint, OutpointParseError}; + +use crate::LIB_NAME_SSID; + +// TODO: Move to BP Seals; generalize +#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] +#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_SSID, tags = custom, dumb = Self::Bitcoin(strict_dumb!()))] +pub enum Seal { + #[strict_type(tag = 0x00)] + #[display("bitcoin:{0}")] + Bitcoin(Outpoint), + + #[strict_type(tag = 0x01)] + #[display("liquid:{0}")] + Liquid(Outpoint), +} + +impl FromStr for Seal { + type Err = OutpointParseError; + + fn from_str(s: &str) -> Result { + if let Some(outpoint) = s.strip_prefix("bitcoin:") { + Outpoint::from_str(outpoint).map(Self::Bitcoin) + } else if let Some(outpoint) = s.strip_prefix("liquid:") { + Outpoint::from_str(outpoint).map(Self::Liquid) + } else { + Outpoint::from_str(s).map(Self::Bitcoin) + } + } +} diff --git a/src/sigs.rs b/src/sigs.rs new file mode 100644 index 0000000..30c52a6 --- /dev/null +++ b/src/sigs.rs @@ -0,0 +1,44 @@ +// Self-sovereign identity (SSID) +// +// SPDX-License-Identifier: Apache-2.0 +// +// Written in 2023-204 by +// Cypher +// +// Copyright 2023-2024 Cyphernet DAO, Switzerland +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use amplify::Bytes32; + +use crate::{IdCert, Identity, Pk, RistrettoPk, RistrettoSig, Sig, Sk, LIB_NAME_SSID}; + +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_SSID)] +pub struct Signature { + pub digest: Bytes32, + pub sig: S, +} + +#[derive(Clone, Eq, PartialEq, Debug)] +#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_SSID)] +pub struct SigCert { + pub sig: Signature<::Sig>, + pub id: IdCert, +} + +impl SigCert { + pub fn identity(&self) -> Identity { self.id.identity() } +}