mirror of
https://github.com/mimblewimble/grin-wallet.git
synced 2025-01-20 19:11:09 +03:00
Slatepack - Pt 2 - Encryption (#411)
* recreate PR from #400 * first tests with slate encryption * simplify slatepack model to contain encryption header in payload, and add de/ser tests * update tests and confirm slatepack encryption working * remove recipient list, add version check warning
This commit is contained in:
parent
9450d2a3b8
commit
2769436117
21 changed files with 2064 additions and 97 deletions
542
Cargo.lock
generated
542
Cargo.lock
generated
|
@ -2,9 +2,9 @@
|
|||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.12.0"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "456d75cbb82da1ad150c8a9d97285ffcd21c9931dcb11e995903e7d75141b38b"
|
||||
checksum = "a49806b9dadc843c61e7c97e72490ad7f7220ae249012fbda9ad0609457c0543"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
@ -15,6 +15,102 @@ version = "1.0.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2"
|
||||
|
||||
[[package]]
|
||||
name = "aead"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4cf01b9b56e767bb57b94ebf91a58b338002963785cdd7013e21c0d4679471e4"
|
||||
dependencies = [
|
||||
"generic-array 0.12.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aes"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54eb1d8fe354e5fc611daf4f2ea97dd45a765f4f1e4512306ec183ae2e8f20c9"
|
||||
dependencies = [
|
||||
"aes-soft",
|
||||
"aesni",
|
||||
"block-cipher-trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aes-ctr"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2e5b0458ea3beae0d1d8c0f3946564f8e10f90646cf78c06b4351052058d1ee"
|
||||
dependencies = [
|
||||
"aes-soft",
|
||||
"aesni",
|
||||
"ctr",
|
||||
"stream-cipher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aes-soft"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfd7e7ae3f9a1fb5c03b389fc6bb9a51400d0c13053f0dca698c832bfd893a0d"
|
||||
dependencies = [
|
||||
"block-cipher-trait",
|
||||
"byteorder",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aesni"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f70a6b5f971e473091ab7cfb5ffac6cde81666c4556751d8d5620ead8abf100"
|
||||
dependencies = [
|
||||
"block-cipher-trait",
|
||||
"opaque-debug",
|
||||
"stream-cipher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "age"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64701e2aa240aa36ad430f8e1b82cd3f226ea0b93185f6fbb9ada0ab12a9a92e"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"aes-ctr",
|
||||
"age-core",
|
||||
"base64 0.11.0",
|
||||
"bcrypt-pbkdf",
|
||||
"bech32",
|
||||
"block-cipher-trait",
|
||||
"block-modes",
|
||||
"c2-chacha",
|
||||
"chacha20poly1305",
|
||||
"cookie-factory",
|
||||
"curve25519-dalek",
|
||||
"hkdf",
|
||||
"hmac 0.7.1",
|
||||
"nom 5.1.1",
|
||||
"radix64",
|
||||
"rand 0.7.3",
|
||||
"scrypt",
|
||||
"secrecy",
|
||||
"sha2 0.8.1",
|
||||
"subtle 2.2.2",
|
||||
"x25519-dalek",
|
||||
"zeroize 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "age-core"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9edc5c56a290116d446475265057ff5bc44490f681ee15cb27111ed47d4afe78"
|
||||
dependencies = [
|
||||
"base64 0.11.0",
|
||||
"cookie-factory",
|
||||
"nom 5.1.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.10"
|
||||
|
@ -99,9 +195,9 @@ version = "0.1.31"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26c4f3195085c36ea8d24d32b2f828d23296a9370a28aa39d111f6f16bef9f3b"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.12",
|
||||
"quote 1.0.5",
|
||||
"syn 1.0.21",
|
||||
"proc-macro2 1.0.13",
|
||||
"quote 1.0.6",
|
||||
"syn 1.0.22",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -165,6 +261,26 @@ version = "0.11.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
|
||||
|
||||
[[package]]
|
||||
name = "bcrypt-pbkdf"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "108e67d628901912875b038f27df25091799ba3b2fb1254a00fde6efb4318313"
|
||||
dependencies = [
|
||||
"blowfish",
|
||||
"byteorder",
|
||||
"crypto-mac 0.7.0",
|
||||
"pbkdf2 0.3.0",
|
||||
"sha2 0.8.1",
|
||||
"zeroize 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bech32"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdcf67bb7ba7797a081cd19009948ab533af7c355d5caf1d08c777582d351e9c"
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.52.0"
|
||||
|
@ -181,8 +297,8 @@ dependencies = [
|
|||
"lazycell",
|
||||
"log",
|
||||
"peeking_take_while",
|
||||
"proc-macro2 1.0.12",
|
||||
"quote 1.0.5",
|
||||
"proc-macro2 1.0.13",
|
||||
"quote 1.0.6",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"shlex",
|
||||
|
@ -256,6 +372,25 @@ dependencies = [
|
|||
"generic-array 0.12.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-cipher-trait"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774"
|
||||
dependencies = [
|
||||
"generic-array 0.12.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-modes"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31aa8410095e39fdb732909fb5730a48d5bd7c2e3cd76bd1b07b3dbea130c529"
|
||||
dependencies = [
|
||||
"block-cipher-trait",
|
||||
"block-padding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-padding"
|
||||
version = "0.1.5"
|
||||
|
@ -265,6 +400,23 @@ dependencies = [
|
|||
"byte-tools 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blowfish"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6aeb80d00f2688459b8542068abd974cfb101e7a82182414a99b5026c0d85cc3"
|
||||
dependencies = [
|
||||
"block-cipher-trait",
|
||||
"byteorder",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bs58"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "476e9cd489f9e121e02ffa6014a8ef220ecb15c05ed23fc34cca13925dc283fb"
|
||||
|
||||
[[package]]
|
||||
name = "built"
|
||||
version = "0.3.2"
|
||||
|
@ -318,10 +470,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "130aac562c0dd69c56b3b1cc8ffd2e17be31d0b6c25b61c96b76231aa23e39e1"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.52"
|
||||
name = "c2-chacha"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d87b23d6a92cd03af510a5ade527033f6aa6fa92161e2d5863a907d4c5e31d"
|
||||
checksum = "217192c943108d8b13bac38a1d51df9ce8a407a3f5a71ab633980665e68fbd9a"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"ppv-lite86",
|
||||
"stream-cipher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.53"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "404b1fe4f65288577753b17e3b36a04596ee784493ec249bf81c7f2d2acd751c"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
]
|
||||
|
@ -332,7 +495,7 @@ version = "0.3.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fce5b5fb86b0c57c20c834c1b412fd09c77c8a59b9473f86272709e78874cd1d"
|
||||
dependencies = [
|
||||
"nom",
|
||||
"nom 4.2.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -341,6 +504,18 @@ version = "0.1.10"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
|
||||
[[package]]
|
||||
name = "chacha20poly1305"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48901293601228db2131606f741db33561f7576b5d19c99cd66222380a7dc863"
|
||||
dependencies = [
|
||||
"aead",
|
||||
"poly1305",
|
||||
"stream-cipher",
|
||||
"zeroize 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.11"
|
||||
|
@ -404,6 +579,12 @@ version = "0.1.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
||||
|
||||
[[package]]
|
||||
name = "cookie-factory"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41f21b581d2f0cb891554812435667bb9610d74feb1a4c6415bf09c28ff0381d"
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.6.4"
|
||||
|
@ -524,6 +705,16 @@ dependencies = [
|
|||
"generic-array 0.9.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-mac"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5"
|
||||
dependencies = [
|
||||
"generic-array 0.12.3",
|
||||
"subtle 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "csv"
|
||||
version = "0.15.0"
|
||||
|
@ -544,6 +735,16 @@ dependencies = [
|
|||
"sct",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ctr"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "022cd691704491df67d25d006fe8eca083098253c4d43516c2206479c58c6736"
|
||||
dependencies = [
|
||||
"block-cipher-trait",
|
||||
"stream-cipher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "curve25519-dalek"
|
||||
version = "2.0.0"
|
||||
|
@ -553,7 +754,7 @@ dependencies = [
|
|||
"byteorder",
|
||||
"digest 0.8.1",
|
||||
"rand_core 0.5.1",
|
||||
"subtle",
|
||||
"subtle 2.2.2",
|
||||
"zeroize 1.1.0",
|
||||
]
|
||||
|
||||
|
@ -744,9 +945,9 @@ version = "0.1.8"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.12",
|
||||
"quote 1.0.5",
|
||||
"syn 1.0.21",
|
||||
"proc-macro2 1.0.13",
|
||||
"quote 1.0.6",
|
||||
"syn 1.0.22",
|
||||
"synstructure 0.12.3",
|
||||
]
|
||||
|
||||
|
@ -770,9 +971,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.6"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
|
@ -872,9 +1073,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "d0b5a30a4328ab5473878237c447333c093297bded83a4983d10f4deea240d39"
|
||||
dependencies = [
|
||||
"proc-macro-hack",
|
||||
"proc-macro2 1.0.12",
|
||||
"quote 1.0.5",
|
||||
"syn 1.0.21",
|
||||
"proc-macro2 1.0.13",
|
||||
"quote 1.0.6",
|
||||
"syn 1.0.22",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -975,7 +1176,7 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
|||
[[package]]
|
||||
name = "grin_api"
|
||||
version = "4.0.0-alpha.1"
|
||||
source = "git+https://github.com/mimblewimble/grin#2c621115612013a68de7bd973a42ec88ae5f44fc"
|
||||
source = "git+https://github.com/mimblewimble/grin#93f5de3d2957f6f30dde8ae8f588efa0754c5ca3"
|
||||
dependencies = [
|
||||
"bytes 0.5.4",
|
||||
"easy-jsonrpc-mw",
|
||||
|
@ -1001,14 +1202,14 @@ dependencies = [
|
|||
"serde_derive",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
"tokio-rustls 0.13.0",
|
||||
"tokio-rustls 0.13.1",
|
||||
"url 1.7.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "grin_chain"
|
||||
version = "4.0.0-alpha.1"
|
||||
source = "git+https://github.com/mimblewimble/grin#2c621115612013a68de7bd973a42ec88ae5f44fc"
|
||||
source = "git+https://github.com/mimblewimble/grin#93f5de3d2957f6f30dde8ae8f588efa0754c5ca3"
|
||||
dependencies = [
|
||||
"bit-vec",
|
||||
"bitflags 1.2.1",
|
||||
|
@ -1031,7 +1232,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "grin_core"
|
||||
version = "4.0.0-alpha.1"
|
||||
source = "git+https://github.com/mimblewimble/grin#2c621115612013a68de7bd973a42ec88ae5f44fc"
|
||||
source = "git+https://github.com/mimblewimble/grin#93f5de3d2957f6f30dde8ae8f588efa0754c5ca3"
|
||||
dependencies = [
|
||||
"blake2-rfc",
|
||||
"byteorder",
|
||||
|
@ -1057,16 +1258,16 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "grin_keychain"
|
||||
version = "4.0.0-alpha.1"
|
||||
source = "git+https://github.com/mimblewimble/grin#2c621115612013a68de7bd973a42ec88ae5f44fc"
|
||||
source = "git+https://github.com/mimblewimble/grin#93f5de3d2957f6f30dde8ae8f588efa0754c5ca3"
|
||||
dependencies = [
|
||||
"blake2-rfc",
|
||||
"byteorder",
|
||||
"digest 0.7.6",
|
||||
"grin_util",
|
||||
"hmac",
|
||||
"hmac 0.6.3",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"pbkdf2",
|
||||
"pbkdf2 0.2.3",
|
||||
"rand 0.6.5",
|
||||
"ripemd160",
|
||||
"serde",
|
||||
|
@ -1079,7 +1280,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "grin_p2p"
|
||||
version = "4.0.0-alpha.1"
|
||||
source = "git+https://github.com/mimblewimble/grin#2c621115612013a68de7bd973a42ec88ae5f44fc"
|
||||
source = "git+https://github.com/mimblewimble/grin#93f5de3d2957f6f30dde8ae8f588efa0754c5ca3"
|
||||
dependencies = [
|
||||
"bitflags 1.2.1",
|
||||
"chrono",
|
||||
|
@ -1100,7 +1301,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "grin_pool"
|
||||
version = "4.0.0-alpha.1"
|
||||
source = "git+https://github.com/mimblewimble/grin#2c621115612013a68de7bd973a42ec88ae5f44fc"
|
||||
source = "git+https://github.com/mimblewimble/grin#93f5de3d2957f6f30dde8ae8f588efa0754c5ca3"
|
||||
dependencies = [
|
||||
"blake2-rfc",
|
||||
"chrono",
|
||||
|
@ -1134,7 +1335,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "grin_store"
|
||||
version = "4.0.0-alpha.1"
|
||||
source = "git+https://github.com/mimblewimble/grin#2c621115612013a68de7bd973a42ec88ae5f44fc"
|
||||
source = "git+https://github.com/mimblewimble/grin#93f5de3d2957f6f30dde8ae8f588efa0754c5ca3"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"croaring-mw",
|
||||
|
@ -1154,7 +1355,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "grin_util"
|
||||
version = "4.0.0-alpha.1"
|
||||
source = "git+https://github.com/mimblewimble/grin#2c621115612013a68de7bd973a42ec88ae5f44fc"
|
||||
source = "git+https://github.com/mimblewimble/grin#93f5de3d2957f6f30dde8ae8f588efa0754c5ca3"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"base64 0.9.3",
|
||||
|
@ -1264,6 +1465,7 @@ dependencies = [
|
|||
"tokio",
|
||||
"url 1.7.2",
|
||||
"uuid",
|
||||
"x25519-dalek",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1298,16 +1500,20 @@ dependencies = [
|
|||
"timer",
|
||||
"tokio",
|
||||
"uuid",
|
||||
"x25519-dalek",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "grin_wallet_libwallet"
|
||||
version = "4.0.0-alpha.1"
|
||||
dependencies = [
|
||||
"age",
|
||||
"base64 0.9.3",
|
||||
"blake2-rfc",
|
||||
"bs58",
|
||||
"byteorder",
|
||||
"chrono",
|
||||
"curve25519-dalek",
|
||||
"ed25519-dalek",
|
||||
"failure",
|
||||
"failure_derive",
|
||||
|
@ -1316,12 +1522,16 @@ dependencies = [
|
|||
"lazy_static",
|
||||
"log",
|
||||
"rand 0.5.6",
|
||||
"regex",
|
||||
"secrecy",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"sha2 0.8.1",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"uuid",
|
||||
"x25519-dalek",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1373,23 +1583,43 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.12"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61565ff7aaace3525556587bd2dc31d4a07071957be715e63ce7b1eccf51a8f4"
|
||||
checksum = "91780f809e750b0a89f5544be56617ff6b1227ee485bcb06ebe10cdf89bd3b71"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hkdf"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fa08a006102488bd9cd5b8013aabe84955cf5ae22e304c2caf655b633aefae3"
|
||||
dependencies = [
|
||||
"digest 0.8.1",
|
||||
"hmac 0.7.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hmac"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "733e1b3ac906631ca01ebb577e9bb0f5e37a454032b9036b5eaea4013ed6f99a"
|
||||
dependencies = [
|
||||
"crypto-mac",
|
||||
"crypto-mac 0.6.2",
|
||||
"digest 0.7.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hmac"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695"
|
||||
dependencies = [
|
||||
"crypto-mac 0.7.0",
|
||||
"digest 0.8.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.1.21"
|
||||
|
@ -1474,7 +1704,7 @@ dependencies = [
|
|||
"rustls 0.16.0",
|
||||
"rustls-native-certs 0.1.0",
|
||||
"tokio",
|
||||
"tokio-rustls 0.12.2",
|
||||
"tokio-rustls 0.12.3",
|
||||
"webpki",
|
||||
]
|
||||
|
||||
|
@ -1492,7 +1722,7 @@ dependencies = [
|
|||
"rustls 0.17.0",
|
||||
"rustls-native-certs 0.3.0",
|
||||
"tokio",
|
||||
"tokio-rustls 0.13.0",
|
||||
"tokio-rustls 0.13.1",
|
||||
"webpki",
|
||||
]
|
||||
|
||||
|
@ -1641,6 +1871,19 @@ version = "1.2.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
|
||||
|
||||
[[package]]
|
||||
name = "lexical-core"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7043aa5c05dd34fb73b47acb8c3708eac428de4545ea3682ed2f11293ebd890"
|
||||
dependencies = [
|
||||
"arrayvec 0.4.12",
|
||||
"cfg-if",
|
||||
"rustc_version 0.2.3",
|
||||
"ryu",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.70"
|
||||
|
@ -1984,7 +2227,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
|
||||
dependencies = [
|
||||
"memchr 2.3.3",
|
||||
"version_check",
|
||||
"version_check 0.1.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "5.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b471253da97532da4b61552249c521e01e736071f71c1a4f7ebbfbf0a06aad6"
|
||||
dependencies = [
|
||||
"lexical-core",
|
||||
"memchr 2.3.3",
|
||||
"version_check 0.9.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2238,13 +2492,23 @@ dependencies = [
|
|||
"base64 0.9.3",
|
||||
"byteorder",
|
||||
"constant_time_eq",
|
||||
"crypto-mac",
|
||||
"crypto-mac 0.6.2",
|
||||
"generic-array 0.9.0",
|
||||
"hmac",
|
||||
"hmac 0.6.3",
|
||||
"rand 0.5.6",
|
||||
"sha2 0.7.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pbkdf2"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"crypto-mac 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "peeking_take_while"
|
||||
version = "0.1.2"
|
||||
|
@ -2303,22 +2567,22 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "0.4.16"
|
||||
version = "0.4.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81d480cb4e89522ccda96d0eed9af94180b7a5f93fb28f66e1fd7d68431663d1"
|
||||
checksum = "edc93aeee735e60ecb40cf740eb319ff23eab1c5748abfdb5c180e4ce49f7791"
|
||||
dependencies = [
|
||||
"pin-project-internal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-internal"
|
||||
version = "0.4.16"
|
||||
version = "0.4.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a82996f11efccb19b685b14b5df818de31c1edcee3daa256ab5775dd98e72feb"
|
||||
checksum = "e58db2081ba5b4c93bd6be09c40fd36cb9193a8336c384f3b40012e531aa7e40"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.12",
|
||||
"quote 1.0.5",
|
||||
"syn 1.0.21",
|
||||
"proc-macro2 1.0.13",
|
||||
"quote 1.0.6",
|
||||
"syn 1.0.22",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2346,10 +2610,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "780fb4b6698bbf9cf2444ea5d22411cef2953f0824b98f33cf454ec5615645bd"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.6"
|
||||
name = "poly1305"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
|
||||
checksum = "b5829f50f48e9ddb79f3f7c3097029d0caee30f8286accb241416df603b080b8"
|
||||
dependencies = [
|
||||
"universal-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea"
|
||||
|
||||
[[package]]
|
||||
name = "pretty_assertions"
|
||||
|
@ -2398,9 +2671,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.12"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8872cf6f48eee44265156c111456a700ab3483686b3f96df4cf5481c89157319"
|
||||
checksum = "53f5ffe53a6b28e37c9c1ce74893477864d64f74778a93a4beb43c8fa167f639"
|
||||
dependencies = [
|
||||
"unicode-xid 0.2.0",
|
||||
]
|
||||
|
@ -2422,11 +2695,21 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.5"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42934bc9c8ab0d3b273a16d8551c8f0fcff46be73276ca083ec2414c15c4ba5e"
|
||||
checksum = "54a21852a652ad6f610c9510194f398ff6f8692e334fd1145fed931f7fbe44ea"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.12",
|
||||
"proc-macro2 1.0.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "radix64"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "999718fa65c3be3a74f3f6dae5a98526ff436ea58a82a574f0de89eecd342bee"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2876,6 +3159,19 @@ version = "1.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "scrypt"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "656c79d0e90d0ab28ac86bf3c3d10bfbbac91450d3f190113b4e76d9fec3cfdd"
|
||||
dependencies = [
|
||||
"byte-tools 0.3.1",
|
||||
"byteorder",
|
||||
"hmac 0.7.1",
|
||||
"pbkdf2 0.3.0",
|
||||
"sha2 0.8.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sct"
|
||||
version = "0.6.0"
|
||||
|
@ -2886,6 +3182,15 @@ dependencies = [
|
|||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "secrecy"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9182278ed645df3477a9c27bfee0621c621aa16f6972635f7f795dae3d81070f"
|
||||
dependencies = [
|
||||
"zeroize 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "0.3.4"
|
||||
|
@ -2976,9 +3281,9 @@ version = "1.0.110"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "818fbf6bfa9a42d3bfcaca148547aa00c7b915bec71d1757aa2d44ca68771984"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.12",
|
||||
"quote 1.0.5",
|
||||
"syn 1.0.21",
|
||||
"proc-macro2 1.0.13",
|
||||
"quote 1.0.6",
|
||||
"syn 1.0.22",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3117,6 +3422,21 @@ version = "1.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f3eb36b47e512f8f1c9e3d10c2c1965bc992bd9cdb024fa581e2194501c83d3"
|
||||
|
||||
[[package]]
|
||||
name = "stream-cipher"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8131256a5896cabcf5eb04f4d6dacbe1aefda854b0d9896e09cb58829ec5638c"
|
||||
dependencies = [
|
||||
"generic-array 0.12.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
|
@ -3141,6 +3461,12 @@ dependencies = [
|
|||
"syn 0.15.44",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee"
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.2.2"
|
||||
|
@ -3166,12 +3492,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.21"
|
||||
version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4696caa4048ac7ce2bcd2e484b3cef88c1004e41b8e945a277e2c25dc0b72060"
|
||||
checksum = "1425de3c33b0941002740a420b1a906a350b88d08b82b2c8a01035a3f9447bac"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.12",
|
||||
"quote 1.0.5",
|
||||
"proc-macro2 1.0.13",
|
||||
"quote 1.0.6",
|
||||
"unicode-xid 0.2.0",
|
||||
]
|
||||
|
||||
|
@ -3193,9 +3519,9 @@ version = "0.12.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.12",
|
||||
"quote 1.0.5",
|
||||
"syn 1.0.21",
|
||||
"proc-macro2 1.0.13",
|
||||
"quote 1.0.6",
|
||||
"syn 1.0.22",
|
||||
"unicode-xid 0.2.0",
|
||||
]
|
||||
|
||||
|
@ -3253,7 +3579,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "8e51065bafd2abe106b6036483b69d1741f4a1ec56ce8a2378de341637de689e"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"nom",
|
||||
"nom 4.2.3",
|
||||
"phf",
|
||||
"phf_codegen",
|
||||
]
|
||||
|
@ -3269,22 +3595,22 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.17"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "467e5ff447618a916519a4e0d62772ab14f434897f3d63f05d8700ef1e9b22c1"
|
||||
checksum = "5976891d6950b4f68477850b5b9e5aa64d955961466f9e174363f573e54e8ca7"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.17"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e63c1091225b9834089b429bc4a2e01223470e3183e891582909e9d1c4cb55d9"
|
||||
checksum = "ab81dbd1cd69cd2ce22ecfbdd3bdb73334ba25350649408cc6c085f46d89573d"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.12",
|
||||
"quote 1.0.5",
|
||||
"syn 1.0.21",
|
||||
"proc-macro2 1.0.13",
|
||||
"quote 1.0.6",
|
||||
"syn 1.0.22",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3366,16 +3692,16 @@ version = "0.2.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0c3acc6aa564495a0f2e1d59fab677cd7f81a19994cfc7f3ad0e64301560389"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.12",
|
||||
"quote 1.0.5",
|
||||
"syn 1.0.21",
|
||||
"proc-macro2 1.0.13",
|
||||
"quote 1.0.6",
|
||||
"syn 1.0.22",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-rustls"
|
||||
version = "0.12.2"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "141afec0978abae6573065a48882c6bae44c5cc61db9b511ac4abf6a09bfd9cc"
|
||||
checksum = "3068d891551949b37681724d6b73666787cc63fa8e255c812a41d2513aff9775"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"rustls 0.16.0",
|
||||
|
@ -3385,9 +3711,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tokio-rustls"
|
||||
version = "0.13.0"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4adb8b3e5f86b707f1b54e7c15b6de52617a823608ccda98a15d3a24222f265a"
|
||||
checksum = "15cb62a0d2770787abc96e99c1cd98fcf17f94959f3af63ca85bdfb203f051b4"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"rustls 0.17.0",
|
||||
|
@ -3512,6 +3838,16 @@ version = "0.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
||||
|
||||
[[package]]
|
||||
name = "universal-hash"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df0c900f2f9b4116803415878ff48b63da9edb268668e08cf9292d7503114a01"
|
||||
dependencies = [
|
||||
"generic-array 0.12.3",
|
||||
"subtle 2.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unsafe-any"
|
||||
version = "0.4.2"
|
||||
|
@ -3583,6 +3919,12 @@ version = "0.1.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce"
|
||||
|
||||
[[package]]
|
||||
name = "void"
|
||||
version = "1.0.2"
|
||||
|
@ -3635,9 +3977,9 @@ dependencies = [
|
|||
"bumpalo",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"proc-macro2 1.0.12",
|
||||
"quote 1.0.5",
|
||||
"syn 1.0.21",
|
||||
"proc-macro2 1.0.13",
|
||||
"quote 1.0.6",
|
||||
"syn 1.0.22",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
|
@ -3647,7 +3989,7 @@ version = "0.2.62"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2cd85aa2c579e8892442954685f0d801f9129de24fa2136b2c6a539c76b65776"
|
||||
dependencies = [
|
||||
"quote 1.0.5",
|
||||
"quote 1.0.6",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
|
@ -3657,9 +3999,9 @@ version = "0.2.62"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8eb197bd3a47553334907ffd2f16507b4f4f01bbec3ac921a7719e0decdfe72a"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.12",
|
||||
"quote 1.0.5",
|
||||
"syn 1.0.21",
|
||||
"proc-macro2 1.0.13",
|
||||
"quote 1.0.6",
|
||||
"syn 1.0.22",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
@ -3752,6 +4094,17 @@ dependencies = [
|
|||
"winapi-build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "x25519-dalek"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "637ff90c9540fa3073bb577e65033069e4bae7c79d49d74aa3ffdf5342a53217"
|
||||
dependencies = [
|
||||
"curve25519-dalek",
|
||||
"rand_core 0.5.1",
|
||||
"zeroize 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yaml-rust"
|
||||
version = "0.3.5"
|
||||
|
@ -3773,7 +4126,7 @@ version = "0.9.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "45af6a010d13e4cf5b54c94ba5a2b2eba5596b9e46bf5875612d332a1f2b3f86"
|
||||
dependencies = [
|
||||
"zeroize_derive",
|
||||
"zeroize_derive 0.9.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3781,6 +4134,9 @@ name = "zeroize"
|
|||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3cbac2ed2ba24cc90f5e06485ac8c7c1e5449fe8911aef4d8877218af021a5b8"
|
||||
dependencies = [
|
||||
"zeroize_derive 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize_derive"
|
||||
|
@ -3794,6 +4150,18 @@ dependencies = [
|
|||
"synstructure 0.10.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize_derive"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de251eec69fc7c1bc3923403d18ececb929380e016afe103da75f396704f8ca2"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.13",
|
||||
"quote 1.0.6",
|
||||
"syn 1.0.22",
|
||||
"synstructure 0.12.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "0.5.5"
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
use chrono::prelude::*;
|
||||
use ed25519_dalek::PublicKey as DalekPublicKey;
|
||||
use ed25519_dalek::SecretKey as DalekSecretKey;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::config::{TorConfig, WalletConfig};
|
||||
|
@ -1913,6 +1914,16 @@ where
|
|||
owner::get_public_proof_address(self.wallet_inst.clone(), keychain_mask, derivation_index)
|
||||
}
|
||||
|
||||
// TODO: Doc
|
||||
/// get public proof a
|
||||
pub fn get_secret_key(
|
||||
&self,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
derivation_index: u32,
|
||||
) -> Result<DalekSecretKey, Error> {
|
||||
owner::get_secret_key(self.wallet_inst.clone(), keychain_mask, derivation_index)
|
||||
}
|
||||
|
||||
/// Helper function to convert an Onion v3 address to a payment proof address (essentially
|
||||
/// exctacting and verifying the public key)
|
||||
///
|
||||
|
|
|
@ -36,3 +36,6 @@ grin_wallet_api = { path = "../api", version = "4.0.0-alpha.1" }
|
|||
grin_wallet_impls = { path = "../impls", version = "4.0.0-alpha.1" }
|
||||
grin_wallet_libwallet = { path = "../libwallet", version = "4.0.0-alpha.1" }
|
||||
grin_wallet_config = { path = "../config", version = "4.0.0-alpha.1" }
|
||||
|
||||
[dev-dependencies]
|
||||
x25519-dalek = "0.6"
|
||||
|
|
|
@ -93,7 +93,6 @@ fn no_change_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
api.tx_lock_outputs(m, &slate)?;
|
||||
slate = api.finalize_tx(m, &slate)?;
|
||||
println!("Posted Slate: {:?}", slate);
|
||||
println!("Posted TX: {}", slate);
|
||||
stored_excess = Some(slate.tx.as_ref().unwrap().body.kernels[0].excess);
|
||||
api.post_tx(m, &slate, false)?;
|
||||
Ok(())
|
||||
|
|
526
controller/tests/slatepack.rs
Normal file
526
controller/tests/slatepack.rs
Normal file
|
@ -0,0 +1,526 @@
|
|||
// Copyright 2019 The Grin Developers
|
||||
// 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.
|
||||
|
||||
//! Test a wallet file send/recieve
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate grin_wallet_controller as wallet;
|
||||
extern crate grin_wallet_impls as impls;
|
||||
|
||||
use grin_wallet_libwallet as libwallet;
|
||||
use grin_wallet_util::grin_core as core;
|
||||
use grin_wallet_util::OnionV3Address;
|
||||
|
||||
use impls::test_framework::{self, LocalWalletClient};
|
||||
use impls::{
|
||||
PathToSlatepack, PathToSlatepackArmored, SlateGetter as _, SlatePutter as _, SlatepackArgs,
|
||||
};
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use grin_wallet_libwallet::{InitTxArgs, IssueInvoiceTxArgs, Slate, Slatepack};
|
||||
|
||||
use x25519_dalek::PublicKey as xDalekPublicKey;
|
||||
use x25519_dalek::StaticSecret;
|
||||
|
||||
#[macro_use]
|
||||
mod common;
|
||||
use common::{clean_output_dir, create_wallet_proxy, setup};
|
||||
|
||||
fn output_slatepack(
|
||||
slate: &Slate,
|
||||
file: &str,
|
||||
armored: bool,
|
||||
use_bin: bool,
|
||||
sender: Option<xDalekPublicKey>,
|
||||
recipients: Vec<xDalekPublicKey>,
|
||||
) -> Result<(), libwallet::Error> {
|
||||
if armored {
|
||||
let file = format!("{}.armored", file);
|
||||
let args = SlatepackArgs {
|
||||
pathbuf: file.into(),
|
||||
sender,
|
||||
recipients,
|
||||
dec_key: None,
|
||||
};
|
||||
PathToSlatepackArmored::new(args).put_tx(&slate, use_bin)
|
||||
} else {
|
||||
let args = SlatepackArgs {
|
||||
pathbuf: file.into(),
|
||||
sender,
|
||||
recipients,
|
||||
dec_key: None,
|
||||
};
|
||||
PathToSlatepack::new(args).put_tx(&slate, use_bin)
|
||||
}
|
||||
}
|
||||
|
||||
fn slate_from_packed(
|
||||
file: &str,
|
||||
armored: bool,
|
||||
dec_key: Option<&StaticSecret>,
|
||||
) -> Result<(Slatepack, Slate), libwallet::Error> {
|
||||
if armored {
|
||||
let file = format!("{}.armored", file);
|
||||
let args = SlatepackArgs {
|
||||
pathbuf: file.into(),
|
||||
sender: None,
|
||||
recipients: vec![],
|
||||
dec_key,
|
||||
};
|
||||
let pts = PathToSlatepackArmored::new(args);
|
||||
Ok((pts.get_slatepack()?, pts.get_tx()?.0))
|
||||
} else {
|
||||
let args = SlatepackArgs {
|
||||
pathbuf: file.into(),
|
||||
sender: None,
|
||||
recipients: vec![],
|
||||
dec_key,
|
||||
};
|
||||
let pts = PathToSlatepack::new(args);
|
||||
Ok((pts.get_slatepack()?, pts.get_tx()?.0))
|
||||
}
|
||||
}
|
||||
|
||||
/// self send impl
|
||||
fn slatepack_exchange_test_impl(
|
||||
test_dir: &'static str,
|
||||
use_bin: bool,
|
||||
use_armored: bool,
|
||||
use_encryption: bool,
|
||||
) -> Result<(), libwallet::Error> {
|
||||
// Create a new proxy to simulate server and wallet responses
|
||||
let mut wallet_proxy = create_wallet_proxy(test_dir);
|
||||
let chain = wallet_proxy.chain.clone();
|
||||
let stopper = wallet_proxy.running.clone();
|
||||
|
||||
// Create a new wallet test client, and set its queues to communicate with the
|
||||
// proxy
|
||||
create_wallet_and_add!(
|
||||
client1,
|
||||
wallet1,
|
||||
mask1_i,
|
||||
test_dir,
|
||||
"wallet1",
|
||||
None,
|
||||
&mut wallet_proxy,
|
||||
false
|
||||
);
|
||||
let mask1 = (&mask1_i).as_ref();
|
||||
create_wallet_and_add!(
|
||||
client2,
|
||||
wallet2,
|
||||
mask2_i,
|
||||
test_dir,
|
||||
"wallet2",
|
||||
None,
|
||||
&mut wallet_proxy,
|
||||
false
|
||||
);
|
||||
let mask2 = (&mask2_i).as_ref();
|
||||
|
||||
// Set the wallet proxy listener running
|
||||
thread::spawn(move || {
|
||||
if let Err(e) = wallet_proxy.run() {
|
||||
error!("Wallet Proxy error: {}", e);
|
||||
}
|
||||
});
|
||||
|
||||
// few values to keep things shorter
|
||||
let reward = core::consensus::REWARD;
|
||||
|
||||
// add some accounts
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
|
||||
api.create_account_path(m, "mining")?;
|
||||
api.create_account_path(m, "listener")?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// add some accounts
|
||||
wallet::controller::owner_single_use(Some(wallet2.clone()), mask2, None, |api, m| {
|
||||
api.create_account_path(m, "account1")?;
|
||||
api.create_account_path(m, "account2")?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// Get some mining done
|
||||
{
|
||||
wallet_inst!(wallet1, w);
|
||||
w.set_parent_key_id_by_name("mining")?;
|
||||
}
|
||||
let mut bh = 10u64;
|
||||
let _ =
|
||||
test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, bh as usize, false);
|
||||
|
||||
let (recipients_1, dec_key_1, sender_1) = match use_encryption {
|
||||
true => {
|
||||
let mut rec_address = xDalekPublicKey::from([0u8; 32]);
|
||||
let mut sec_key = StaticSecret::from([0u8; 32]);
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
|
||||
let ed25519_sec_key = api.get_secret_key(m, 0)?;
|
||||
let mut b = [0u8; 32];
|
||||
b.copy_from_slice(&ed25519_sec_key.as_ref()[0..32]);
|
||||
sec_key = StaticSecret::from(b);
|
||||
rec_address = xDalekPublicKey::from(&sec_key);
|
||||
Ok(())
|
||||
})?;
|
||||
(vec![rec_address], Some(sec_key), Some(rec_address.clone()))
|
||||
}
|
||||
false => (vec![], None, None),
|
||||
};
|
||||
|
||||
let (recipients_2, dec_key_2, sender_2) = match use_encryption {
|
||||
true => {
|
||||
let mut rec_address = xDalekPublicKey::from([0u8; 32]);
|
||||
let mut sec_key = StaticSecret::from([0u8; 32]);
|
||||
wallet::controller::owner_single_use(Some(wallet2.clone()), mask2, None, |api, m| {
|
||||
let ed25519_sec_key = api.get_secret_key(m, 0)?;
|
||||
let mut b = [0u8; 32];
|
||||
b.copy_from_slice(&ed25519_sec_key.as_ref()[0..32]);
|
||||
sec_key = StaticSecret::from(b);
|
||||
rec_address = xDalekPublicKey::from(&sec_key);
|
||||
Ok(())
|
||||
})?;
|
||||
(vec![rec_address], Some(sec_key), Some(rec_address.clone()))
|
||||
}
|
||||
false => (vec![], None, None),
|
||||
};
|
||||
|
||||
let (send_file, receive_file, final_file) = match use_bin {
|
||||
false => (
|
||||
format!("{}/standard_S1.slatepack", test_dir),
|
||||
format!("{}/standard_S2.slatepack", test_dir),
|
||||
format!("{}/standard_S3.slatepack", test_dir),
|
||||
),
|
||||
true => (
|
||||
format!("{}/standard_S1.slatepackbin", test_dir),
|
||||
format!("{}/standard_S2.slatepackbin", test_dir),
|
||||
format!("{}/standard_S3.slatepackbin", test_dir),
|
||||
),
|
||||
};
|
||||
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
assert!(wallet1_refreshed);
|
||||
assert_eq!(wallet1_info.last_confirmed_height, bh);
|
||||
assert_eq!(wallet1_info.total, bh * reward);
|
||||
// send to send
|
||||
let args = InitTxArgs {
|
||||
src_acct_name: Some("mining".to_owned()),
|
||||
amount: reward * 2,
|
||||
minimum_confirmations: 2,
|
||||
max_outputs: 500,
|
||||
num_change_outputs: 1,
|
||||
selection_strategy_is_use_all: true,
|
||||
..Default::default()
|
||||
};
|
||||
let slate = api.init_send_tx(m, args)?;
|
||||
// output tx file
|
||||
output_slatepack(
|
||||
&slate,
|
||||
&send_file,
|
||||
use_armored,
|
||||
use_bin,
|
||||
sender_1,
|
||||
recipients_2.clone(),
|
||||
)?;
|
||||
api.tx_lock_outputs(m, &slate)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// Get some mining done
|
||||
{
|
||||
wallet_inst!(wallet2, w);
|
||||
w.set_parent_key_id_by_name("account1")?;
|
||||
}
|
||||
|
||||
let (mut slatepack, mut slate) =
|
||||
slate_from_packed(&send_file, use_armored, (&dec_key_2).as_ref())?;
|
||||
|
||||
// wallet 2 receives file, completes, sends file back
|
||||
wallet::controller::foreign_single_use(wallet2.clone(), mask2_i.clone(), |api| {
|
||||
slate = api.receive_tx(&slate, None)?;
|
||||
output_slatepack(
|
||||
&slate,
|
||||
&receive_file,
|
||||
use_armored,
|
||||
use_bin,
|
||||
// re-encrypt for sender!
|
||||
sender_2,
|
||||
match slatepack.sender {
|
||||
Some(s) => vec![s.clone()],
|
||||
None => vec![],
|
||||
},
|
||||
)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// wallet 1 finalises and posts
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
|
||||
let (_, mut slate) = slate_from_packed(&receive_file, use_armored, (&dec_key_1).as_ref())?;
|
||||
slate = api.finalize_tx(m, &slate)?;
|
||||
// Output final file for reference
|
||||
output_slatepack(&slate, &final_file, use_armored, use_bin, None, vec![])?;
|
||||
api.post_tx(m, &slate, false)?;
|
||||
bh += 1;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
|
||||
bh += 3;
|
||||
|
||||
// Check total in mining account
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
assert!(wallet1_refreshed);
|
||||
assert_eq!(wallet1_info.last_confirmed_height, bh);
|
||||
assert_eq!(wallet1_info.total, bh * reward - reward * 2);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// Check total in 'wallet 2' account
|
||||
wallet::controller::owner_single_use(Some(wallet2.clone()), mask2, None, |api, m| {
|
||||
let (wallet2_refreshed, wallet2_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
assert!(wallet2_refreshed);
|
||||
assert_eq!(wallet2_info.last_confirmed_height, bh);
|
||||
assert_eq!(wallet2_info.total, 2 * reward);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// Now other types of exchange, for reference
|
||||
// Invoice transaction
|
||||
let (send_file, receive_file, final_file) = match use_bin {
|
||||
false => (
|
||||
format!("{}/invoice_I1.slatepack", test_dir),
|
||||
format!("{}/invoice_I2.slatepack", test_dir),
|
||||
format!("{}/invoice_I3.slatepack", test_dir),
|
||||
),
|
||||
true => (
|
||||
format!("{}/invoice_I1.slatepackbin", test_dir),
|
||||
format!("{}/invoice_I2.slatepackbin", test_dir),
|
||||
format!("{}/invoice_I3.slatepackbin", test_dir),
|
||||
),
|
||||
};
|
||||
|
||||
let mut slate = Slate::blank(2, true);
|
||||
|
||||
wallet::controller::owner_single_use(Some(wallet2.clone()), mask2, None, |api, m| {
|
||||
let args = IssueInvoiceTxArgs {
|
||||
amount: 1000000000,
|
||||
..Default::default()
|
||||
};
|
||||
slate = api.issue_invoice_tx(m, args)?;
|
||||
output_slatepack(
|
||||
&slate,
|
||||
&send_file,
|
||||
use_armored,
|
||||
use_bin,
|
||||
sender_2,
|
||||
recipients_1.clone(),
|
||||
)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
|
||||
let args = InitTxArgs {
|
||||
src_acct_name: None,
|
||||
amount: slate.amount,
|
||||
minimum_confirmations: 2,
|
||||
max_outputs: 500,
|
||||
num_change_outputs: 1,
|
||||
selection_strategy_is_use_all: true,
|
||||
..Default::default()
|
||||
};
|
||||
let res = slate_from_packed(&send_file, use_armored, (&dec_key_1).as_ref())?;
|
||||
slatepack = res.0;
|
||||
slate = res.1;
|
||||
slate = api.process_invoice_tx(m, &slate, args)?;
|
||||
api.tx_lock_outputs(m, &slate)?;
|
||||
output_slatepack(
|
||||
&slate,
|
||||
&receive_file,
|
||||
use_armored,
|
||||
use_bin,
|
||||
sender_1,
|
||||
match slatepack.sender {
|
||||
Some(s) => vec![s.clone()],
|
||||
None => vec![],
|
||||
},
|
||||
)?;
|
||||
Ok(())
|
||||
})?;
|
||||
wallet::controller::foreign_single_use(wallet2.clone(), mask2_i.clone(), |api| {
|
||||
// Wallet 2 receives the invoice transaction
|
||||
let res = slate_from_packed(&receive_file, use_armored, (&dec_key_2).as_ref())?;
|
||||
slate = res.1;
|
||||
slate = api.finalize_invoice_tx(&slate)?;
|
||||
output_slatepack(&slate, &final_file, use_armored, use_bin, None, vec![])?;
|
||||
Ok(())
|
||||
})?;
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
|
||||
api.post_tx(m, &slate, false)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// Standard, with payment proof
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
|
||||
let (send_file, receive_file, final_file) = match use_bin {
|
||||
false => (
|
||||
format!("{}/standard_pp_S1.slatepack", test_dir),
|
||||
format!("{}/standard_pp_S2.slatepack", test_dir),
|
||||
format!("{}/standard_pp_S3.slatepack", test_dir),
|
||||
),
|
||||
true => (
|
||||
format!("{}/standard_pp_S1.slatepackbin", test_dir),
|
||||
format!("{}/standard_pp_S2.slatepackbin", test_dir),
|
||||
format!("{}/standard_pp_S3.slatepackbin", test_dir),
|
||||
),
|
||||
};
|
||||
|
||||
let mut slate = Slate::blank(2, true);
|
||||
let mut address = None;
|
||||
wallet::controller::owner_single_use(Some(wallet2.clone()), mask2, None, |api, m| {
|
||||
address = Some(api.get_public_proof_address(m, 0)?);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
let address = OnionV3Address::from_bytes(address.as_ref().unwrap().to_bytes());
|
||||
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
|
||||
// send to send
|
||||
let args = InitTxArgs {
|
||||
src_acct_name: Some("mining".to_owned()),
|
||||
amount: reward,
|
||||
minimum_confirmations: 2,
|
||||
max_outputs: 500,
|
||||
num_change_outputs: 1,
|
||||
selection_strategy_is_use_all: true,
|
||||
payment_proof_recipient_address: Some(address.clone()),
|
||||
..Default::default()
|
||||
};
|
||||
let slate = api.init_send_tx(m, args)?;
|
||||
output_slatepack(
|
||||
&slate,
|
||||
&send_file,
|
||||
use_armored,
|
||||
use_bin,
|
||||
sender_1,
|
||||
recipients_2.clone(),
|
||||
)?;
|
||||
api.tx_lock_outputs(m, &slate)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
wallet::controller::foreign_single_use(wallet2.clone(), mask2_i.clone(), |api| {
|
||||
let res = slate_from_packed(&send_file, use_armored, (&dec_key_2).as_ref())?;
|
||||
slatepack = res.0;
|
||||
slate = res.1;
|
||||
slate = api.receive_tx(&slate, None)?;
|
||||
output_slatepack(
|
||||
&slate,
|
||||
&receive_file,
|
||||
use_armored,
|
||||
use_bin,
|
||||
sender_2,
|
||||
match slatepack.sender {
|
||||
Some(s) => vec![s.clone()],
|
||||
None => vec![],
|
||||
},
|
||||
)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// wallet 1 finalises and posts
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
|
||||
let res = slate_from_packed(&receive_file, use_armored, (&dec_key_1).as_ref())?;
|
||||
slate = res.1;
|
||||
slate = api.finalize_tx(m, &slate)?;
|
||||
// Output final file for reference
|
||||
output_slatepack(&slate, &final_file, use_armored, use_bin, None, vec![])?;
|
||||
api.post_tx(m, &slate, false)?;
|
||||
bh += 1;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// let logging finish
|
||||
stopper.store(false, Ordering::Relaxed);
|
||||
thread::sleep(Duration::from_millis(200));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn slatepack_exchange_json() {
|
||||
let test_dir = "test_output/slatepack_exchange_json";
|
||||
setup(test_dir);
|
||||
// Json output
|
||||
if let Err(e) = slatepack_exchange_test_impl(test_dir, false, false, false) {
|
||||
panic!("Libwallet Error: {} - {}", e, e.backtrace().unwrap());
|
||||
}
|
||||
clean_output_dir(test_dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn slatepack_exchange_bin() {
|
||||
let test_dir = "test_output/slatepack_exchange_bin";
|
||||
setup(test_dir);
|
||||
// Bin output
|
||||
if let Err(e) = slatepack_exchange_test_impl(test_dir, true, false, false) {
|
||||
panic!("Libwallet Error: {} - {}", e, e.backtrace().unwrap());
|
||||
}
|
||||
clean_output_dir(test_dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn slatepack_exchange_armored() {
|
||||
let test_dir = "test_output/slatepack_exchange_armored";
|
||||
setup(test_dir);
|
||||
// Bin output
|
||||
if let Err(e) = slatepack_exchange_test_impl(test_dir, true, true, false) {
|
||||
panic!("Libwallet Error: {} - {}", e, e.backtrace().unwrap());
|
||||
}
|
||||
clean_output_dir(test_dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn slatepack_exchange_json_enc() {
|
||||
let test_dir = "test_output/slatepack_exchange_json_enc";
|
||||
setup(test_dir);
|
||||
// Json output
|
||||
if let Err(e) = slatepack_exchange_test_impl(test_dir, false, false, true) {
|
||||
panic!("Libwallet Error: {} - {}", e, e.backtrace().unwrap());
|
||||
}
|
||||
clean_output_dir(test_dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn slatepack_exchange_bin_enc() {
|
||||
let test_dir = "test_output/slatepack_exchange_bin_enc";
|
||||
setup(test_dir);
|
||||
// Bin output
|
||||
if let Err(e) = slatepack_exchange_test_impl(test_dir, true, false, true) {
|
||||
panic!("Libwallet Error: {} - {}", e, e.backtrace().unwrap());
|
||||
}
|
||||
clean_output_dir(test_dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn slatepack_exchange_armored_enc() {
|
||||
let test_dir = "test_output/slatepack_exchange_armored_enc";
|
||||
setup(test_dir);
|
||||
// Bin output
|
||||
if let Err(e) = slatepack_exchange_test_impl(test_dir, true, true, true) {
|
||||
panic!("Libwallet Error: {} - {}", e, e.backtrace().unwrap());
|
||||
}
|
||||
clean_output_dir(test_dir);
|
||||
}
|
|
@ -35,6 +35,7 @@ byteorder = "1"
|
|||
hyper = "0.13"
|
||||
hyper-socks2 = "0.4"
|
||||
ed25519-dalek = "1.0.0-pre.1"
|
||||
x25519-dalek = "0.6"
|
||||
data-encoding = "2"
|
||||
regex = "1.3"
|
||||
timer = "0.2"
|
||||
|
|
|
@ -16,13 +16,13 @@
|
|||
use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
|
||||
use crate::client_utils::byte_ser;
|
||||
use crate::libwallet::slate_versions::v3::SlateV3;
|
||||
use crate::libwallet::slate_versions::v4::SlateV4;
|
||||
use crate::libwallet::{
|
||||
Error, ErrorKind, Slate, SlateState, SlateVersion, VersionedBinSlate, VersionedSlate,
|
||||
};
|
||||
use crate::{SlateGetter, SlatePutter};
|
||||
use grin_wallet_util::byte_ser;
|
||||
use std::convert::TryFrom;
|
||||
use std::path::PathBuf;
|
||||
|
||||
|
|
|
@ -15,10 +15,12 @@
|
|||
mod file;
|
||||
pub mod http;
|
||||
mod keybase;
|
||||
mod slatepack;
|
||||
|
||||
pub use self::file::PathToSlate;
|
||||
pub use self::http::{HttpSlateSender, SchemeNotHttp};
|
||||
pub use self::keybase::{KeybaseAllChannels, KeybaseChannel};
|
||||
pub use self::slatepack::{PathToSlatepack, PathToSlatepackArmored, SlatepackArgs};
|
||||
|
||||
use crate::config::{TorConfig, WalletConfig};
|
||||
use crate::libwallet::{Error, ErrorKind, Slate};
|
||||
|
|
169
impls/src/adapters/slatepack.rs
Normal file
169
impls/src/adapters/slatepack.rs
Normal file
|
@ -0,0 +1,169 @@
|
|||
// Copyright 2020 The Grin Developers
|
||||
//
|
||||
// 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::convert::TryFrom;
|
||||
/// Slatepack Output 'plugin' implementation
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use x25519_dalek::PublicKey as xDalekPublicKey;
|
||||
use x25519_dalek::StaticSecret;
|
||||
|
||||
use crate::libwallet::{
|
||||
Error, ErrorKind, Slate, SlateVersion, Slatepack, SlatepackArmor, SlatepackBin,
|
||||
VersionedBinSlate, VersionedSlate,
|
||||
};
|
||||
use crate::{SlateGetter, SlatePutter};
|
||||
use grin_wallet_util::byte_ser;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SlatepackArgs<'a> {
|
||||
pub pathbuf: PathBuf,
|
||||
pub sender: Option<xDalekPublicKey>,
|
||||
pub recipients: Vec<xDalekPublicKey>,
|
||||
pub dec_key: Option<&'a StaticSecret>,
|
||||
}
|
||||
|
||||
pub struct PathToSlatepack<'a>(SlatepackArgs<'a>);
|
||||
|
||||
impl<'a> PathToSlatepack<'a> {
|
||||
/// Create with pathbuf and recipients
|
||||
pub fn new(args: SlatepackArgs<'a>) -> Self {
|
||||
Self(args)
|
||||
}
|
||||
|
||||
pub fn get_slatepack_file_contents(&self) -> Result<Vec<u8>, Error> {
|
||||
let mut pub_tx_f = File::open(&self.0.pathbuf)?;
|
||||
let mut data = Vec::new();
|
||||
pub_tx_f.read_to_end(&mut data)?;
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
// return slatepack itself
|
||||
pub fn deser_slatepack(&self, data: Vec<u8>) -> Result<Slatepack, Error> {
|
||||
// try as bin first, then as json
|
||||
let bin_res = byte_ser::from_bytes::<SlatepackBin>(&data);
|
||||
match bin_res {
|
||||
Err(e) => debug!("Not a valid binary slatepack: {} - Will try JSON", e),
|
||||
Ok(s) => return Ok(s.0),
|
||||
}
|
||||
// Otherwise try json
|
||||
let content = String::from_utf8(data).map_err(|_| ErrorKind::SlatepackDeser)?;
|
||||
let slatepack: Slatepack = serde_json::from_str(&content).map_err(|e| {
|
||||
error!("Error reading JSON Slatepack: {}", e);
|
||||
ErrorKind::SlatepackDeser
|
||||
})?;
|
||||
slatepack.ver_check_warn();
|
||||
Ok(slatepack)
|
||||
}
|
||||
|
||||
pub fn get_slatepack(&self) -> Result<Slatepack, Error> {
|
||||
let data = self.get_slatepack_file_contents()?;
|
||||
self.deser_slatepack(data)
|
||||
}
|
||||
|
||||
// Create slatepack from slate and args
|
||||
pub fn create_slatepack(&self, slate: &Slate) -> Result<Slatepack, Error> {
|
||||
let out_slate = VersionedSlate::into_version(slate.clone(), SlateVersion::V4)?;
|
||||
let bin_slate =
|
||||
VersionedBinSlate::try_from(out_slate).map_err(|_| ErrorKind::SlatepackSer)?;
|
||||
let mut slatepack = Slatepack::default();
|
||||
slatepack.payload = byte_ser::to_bytes(&bin_slate).map_err(|_| ErrorKind::SlatepackSer)?;
|
||||
slatepack.sender = self.0.sender;
|
||||
slatepack.try_encrypt_payload(self.0.recipients.clone())?;
|
||||
Ok(slatepack)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SlatePutter for PathToSlatepack<'a> {
|
||||
fn put_tx(&self, slate: &Slate, as_bin: bool) -> Result<(), Error> {
|
||||
let slatepack = self.create_slatepack(slate)?;
|
||||
let mut pub_tx = File::create(&self.0.pathbuf)?;
|
||||
if as_bin {
|
||||
pub_tx.write_all(
|
||||
&byte_ser::to_bytes(&SlatepackBin(slatepack))
|
||||
.map_err(|_| ErrorKind::SlatepackSer)?,
|
||||
)?;
|
||||
} else {
|
||||
pub_tx.write_all(
|
||||
serde_json::to_string_pretty(&slatepack)
|
||||
.map_err(|_| ErrorKind::SlateSer)?
|
||||
.as_bytes(),
|
||||
)?;
|
||||
}
|
||||
pub_tx.sync_all()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SlateGetter for PathToSlatepack<'a> {
|
||||
fn get_tx(&self) -> Result<(Slate, bool), Error> {
|
||||
let data = self.get_slatepack_file_contents()?;
|
||||
let mut slatepack = self.deser_slatepack(data)?;
|
||||
slatepack.try_decrypt_payload(self.0.dec_key)?;
|
||||
let slate = byte_ser::from_bytes::<VersionedBinSlate>(&slatepack.payload)
|
||||
.map_err(|_| ErrorKind::SlatepackSer)?;
|
||||
Ok((Slate::upgrade(slate.into())?, true))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PathToSlatepackArmored<'a>(SlatepackArgs<'a>);
|
||||
|
||||
impl<'a> PathToSlatepackArmored<'a> {
|
||||
/// Create with pathbuf and recipients
|
||||
pub fn new(args: SlatepackArgs<'a>) -> Self {
|
||||
Self(args)
|
||||
}
|
||||
|
||||
/// decode armor
|
||||
pub fn decode_armored_file(&self) -> Result<Vec<u8>, Error> {
|
||||
let mut pub_sp_armored = File::open(&self.0.pathbuf)?;
|
||||
let mut data = Vec::new();
|
||||
pub_sp_armored.read_to_end(&mut data)?;
|
||||
SlatepackArmor::decode(&String::from_utf8(data).unwrap())
|
||||
}
|
||||
|
||||
// return slatepack
|
||||
pub fn get_slatepack(&self) -> Result<Slatepack, Error> {
|
||||
let data = self.decode_armored_file()?;
|
||||
let pts = PathToSlatepack::new(self.0.clone());
|
||||
pts.deser_slatepack(data)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SlatePutter for PathToSlatepackArmored<'a> {
|
||||
fn put_tx(&self, slate: &Slate, _as_bin: bool) -> Result<(), Error> {
|
||||
let pts = PathToSlatepack::new(self.0.clone());
|
||||
let slatepack = pts.create_slatepack(slate)?;
|
||||
let armored = SlatepackArmor::encode(&slatepack, 3)?;
|
||||
let mut pub_tx = File::create(&self.0.pathbuf)?;
|
||||
pub_tx.write_all(armored.as_bytes())?;
|
||||
pub_tx.sync_all()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SlateGetter for PathToSlatepackArmored<'a> {
|
||||
fn get_tx(&self) -> Result<(Slate, bool), Error> {
|
||||
let mut slatepack = self.get_slatepack()?;
|
||||
slatepack.try_decrypt_payload(self.0.dec_key)?;
|
||||
let slate_bin =
|
||||
byte_ser::from_bytes::<VersionedBinSlate>(&slatepack.payload).map_err(|e| {
|
||||
error!("Error reading slate from armored slatepack: {}", e);
|
||||
ErrorKind::SlatepackDeser
|
||||
})?;
|
||||
Ok((Slate::upgrade(slate_bin.into())?, true))
|
||||
}
|
||||
}
|
|
@ -12,7 +12,6 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
pub mod byte_ser;
|
||||
mod client;
|
||||
pub mod json_rpc;
|
||||
|
||||
|
|
|
@ -44,8 +44,9 @@ pub mod test_framework;
|
|||
pub mod tor;
|
||||
|
||||
pub use crate::adapters::{
|
||||
create_sender, HttpSlateSender, KeybaseAllChannels, KeybaseChannel, PathToSlate, SlateGetter,
|
||||
SlatePutter, SlateReceiver, SlateSender,
|
||||
create_sender, HttpSlateSender, KeybaseAllChannels, KeybaseChannel, PathToSlate,
|
||||
PathToSlatepack, PathToSlatepackArmored, SlateGetter, SlatePutter, SlateReceiver, SlateSender,
|
||||
SlatepackArgs,
|
||||
};
|
||||
pub use crate::backends::{wallet_db_exists, LMDBBackend};
|
||||
pub use crate::error::{Error, ErrorKind};
|
||||
|
|
|
@ -25,8 +25,18 @@ lazy_static = "1"
|
|||
strum = "0.15"
|
||||
strum_macros = "0.15"
|
||||
ed25519-dalek = "1.0.0-pre.1"
|
||||
x25519-dalek = "0.6"
|
||||
byteorder = "1"
|
||||
base64 = "0.9"
|
||||
regex = "1.3"
|
||||
sha2 = "0.8"
|
||||
bs58 = "0.3"
|
||||
age = "0.4"
|
||||
curve25519-dalek = "2.0.0"
|
||||
secrecy = "0.6"
|
||||
|
||||
grin_wallet_util = { path = "../util", version = "4.0.0-alpha.1" }
|
||||
grin_wallet_config = { path = "../config", version = "4.0.0-alpha.1" }
|
||||
|
||||
[dev-dependencies]
|
||||
byteorder = "1.3"
|
||||
|
|
|
@ -20,7 +20,7 @@ use crate::grin_core::core::hash::Hashed;
|
|||
use crate::grin_core::core::Transaction;
|
||||
use crate::grin_util::secp::key::SecretKey;
|
||||
use crate::grin_util::Mutex;
|
||||
use crate::util::OnionV3Address;
|
||||
use crate::util::{OnionV3Address, OnionV3AddressError};
|
||||
|
||||
use crate::api_impl::owner_updater::StatusMessage;
|
||||
use crate::grin_keychain::{Identifier, Keychain};
|
||||
|
@ -93,6 +93,36 @@ where
|
|||
Ok(addr.to_ed25519()?)
|
||||
}
|
||||
|
||||
/// Retrieve the decryption key for the current parent key
|
||||
/// the given index
|
||||
/// set active account
|
||||
pub fn get_secret_key<'a, L, C, K>(
|
||||
wallet_inst: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
index: u32,
|
||||
) -> Result<DalekSecretKey, Error>
|
||||
where
|
||||
L: WalletLCProvider<'a, C, K>,
|
||||
C: NodeClient + 'a,
|
||||
K: Keychain + 'a,
|
||||
{
|
||||
wallet_lock!(wallet_inst, w);
|
||||
let parent_key_id = w.parent_key_id();
|
||||
let k = w.keychain(keychain_mask)?;
|
||||
let sec_addr_key = address::address_from_derivation_path(&k, &parent_key_id, index)?;
|
||||
let d_skey = match DalekSecretKey::from_bytes(&sec_addr_key.0) {
|
||||
Ok(k) => k,
|
||||
Err(e) => {
|
||||
return Err(OnionV3AddressError::InvalidPrivateKey(format!(
|
||||
"Unable to create secret key: {}",
|
||||
e
|
||||
))
|
||||
.into());
|
||||
}
|
||||
};
|
||||
Ok(d_skey)
|
||||
}
|
||||
|
||||
/// retrieve outputs
|
||||
pub fn retrieve_outputs<'a, L, C, K>(
|
||||
wallet_inst: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
|
||||
|
|
|
@ -202,6 +202,14 @@ pub enum ErrorKind {
|
|||
#[fail(display = "Can't Deserialize slate")]
|
||||
SlateDeser,
|
||||
|
||||
/// Can't serialize slate pack
|
||||
#[fail(display = "Can't Serialize slatepack")]
|
||||
SlatepackSer,
|
||||
|
||||
/// Can't deserialize slate
|
||||
#[fail(display = "Can't Deserialize slatepack")]
|
||||
SlatepackDeser,
|
||||
|
||||
/// Unknown slate version
|
||||
#[fail(display = "Unknown Slate Version: {}", _0)]
|
||||
SlateVersion(u16),
|
||||
|
@ -270,6 +278,18 @@ pub enum ErrorKind {
|
|||
#[fail(display = "Unknown Kernel Feature: {}", _0)]
|
||||
UnknownKernelFeatures(u8),
|
||||
|
||||
/// Invalid Slatepack Data
|
||||
#[fail(display = "Invalid Slatepack Data: {}", _0)]
|
||||
InvalidSlatepackData(String),
|
||||
|
||||
/// Slatepack Encryption
|
||||
#[fail(display = "Couldn't encrypt Slatepack: {}", _0)]
|
||||
SlatepackEncryption(String),
|
||||
|
||||
/// age error
|
||||
#[fail(display = "Age error: {}", _0)]
|
||||
Age(String),
|
||||
|
||||
/// Other
|
||||
#[fail(display = "Generic error: {}", _0)]
|
||||
GenericError(String),
|
||||
|
@ -398,3 +418,11 @@ impl From<util::OnionV3AddressError> for Error {
|
|||
Error::from(ErrorKind::OnionV3Address(error))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<age::Error> for Error {
|
||||
fn from(error: age::Error) -> Error {
|
||||
Error {
|
||||
inner: Context::new(ErrorKind::Age(format!("{}", error))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ mod error;
|
|||
mod internal;
|
||||
mod slate;
|
||||
pub mod slate_versions;
|
||||
mod slatepack;
|
||||
mod types;
|
||||
|
||||
pub use crate::error::{Error, ErrorKind};
|
||||
|
@ -60,6 +61,7 @@ pub use crate::slate_versions::{
|
|||
SlateVersion, VersionedBinSlate, VersionedCoinbase, VersionedSlate, CURRENT_SLATE_VERSION,
|
||||
GRIN_BLOCK_HEADER_VERSION,
|
||||
};
|
||||
pub use crate::slatepack::{Slatepack, SlatepackArmor, SlatepackBin};
|
||||
pub use api_impl::owner_updater::StatusMessage;
|
||||
pub use api_impl::types::{
|
||||
BlockFees, InitTxArgs, InitTxSendArgs, IssueInvoiceTxArgs, NodeHeightResult,
|
||||
|
|
|
@ -28,13 +28,22 @@ where
|
|||
serializer.serialize_str(&base64::encode(&bytes))
|
||||
}
|
||||
|
||||
/// Creates a Vec from a base string
|
||||
pub fn bytes_from_base64<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
use serde::de::Error;
|
||||
String::deserialize(deserializer)
|
||||
.and_then(|string| base64::decode(&string).map_err(|err| Error::custom(err.to_string())))
|
||||
}
|
||||
|
||||
/// Creates a BlindingFactor from a base64 string
|
||||
pub fn blindingfactor_from_base64<'de, D>(deserializer: D) -> Result<BlindingFactor, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
use serde::de::Error;
|
||||
|
||||
let val = String::deserialize(deserializer)
|
||||
.and_then(|string| base64::decode(&string).map_err(|err| Error::custom(err.to_string())))?;
|
||||
Ok(BlindingFactor::from_slice(&val))
|
||||
|
@ -280,6 +289,36 @@ pub mod dalek_pubkey_serde {
|
|||
}
|
||||
}
|
||||
|
||||
/// Serializes an x25519 PublicKey to and from hex
|
||||
pub mod dalek_xpubkey_serde {
|
||||
use crate::grin_util::{from_hex, ToHex};
|
||||
use serde::{Deserialize, Deserializer, Serializer};
|
||||
use x25519_dalek::PublicKey as xDalekPublicKey;
|
||||
|
||||
///
|
||||
pub fn serialize<S>(key: &xDalekPublicKey, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(&key.as_bytes().to_hex())
|
||||
}
|
||||
|
||||
///
|
||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<xDalekPublicKey, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
use serde::de::Error;
|
||||
String::deserialize(deserializer)
|
||||
.and_then(|string| from_hex(&string).map_err(|err| Error::custom(err.to_string())))
|
||||
.and_then(|bytes: Vec<u8>| {
|
||||
let mut b = [0u8; 32];
|
||||
b.copy_from_slice(&bytes[0..32]);
|
||||
Ok(xDalekPublicKey::from(b))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Serializes an ed25519 PublicKey to and from base64
|
||||
pub mod dalek_pubkey_base64 {
|
||||
use base64;
|
||||
|
@ -310,6 +349,47 @@ pub mod dalek_pubkey_base64 {
|
|||
}
|
||||
}
|
||||
|
||||
/// Serializes an Option<ed25519_dalek::PublicKey> to and from hex
|
||||
pub mod option_dalek_pubkey_base64 {
|
||||
use base64;
|
||||
use ed25519_dalek::PublicKey as DalekPublicKey;
|
||||
use serde::de::Error;
|
||||
use serde::{Deserialize, Deserializer, Serializer};
|
||||
|
||||
///
|
||||
pub fn serialize<S>(key: &Option<DalekPublicKey>, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
match key {
|
||||
Some(key) => serializer.serialize_str(&base64::encode(&key.to_bytes())),
|
||||
None => serializer.serialize_none(),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<DalekPublicKey>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Option::<String>::deserialize(deserializer).and_then(|res| match res {
|
||||
Some(string) => base64::decode(&string)
|
||||
.map_err(|err| Error::custom(err.to_string()))
|
||||
.and_then(|bytes: Vec<u8>| {
|
||||
let mut b = [0u8; 32];
|
||||
b.copy_from_slice(&bytes[0..32]);
|
||||
DalekPublicKey::from_bytes(&b)
|
||||
.map(Some)
|
||||
.map_err(|err| Error::custom(err.to_string()))
|
||||
}),
|
||||
None => {
|
||||
println!("None fine");
|
||||
Ok(None)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Serializes an Option<ed25519_dalek::PublicKey> to and from hex
|
||||
pub mod option_dalek_pubkey_serde {
|
||||
use ed25519_dalek::PublicKey as DalekPublicKey;
|
||||
|
@ -349,6 +429,43 @@ pub mod option_dalek_pubkey_serde {
|
|||
}
|
||||
}
|
||||
|
||||
/// Serializes an Option<x25519_dalek::PublicKey> to and from hex
|
||||
pub mod option_xdalek_pubkey_serde {
|
||||
use serde::de::Error;
|
||||
use serde::{Deserialize, Deserializer, Serializer};
|
||||
use x25519_dalek::PublicKey as xDalekPublicKey;
|
||||
|
||||
use crate::grin_util::{from_hex, ToHex};
|
||||
|
||||
///
|
||||
pub fn serialize<S>(key: &Option<xDalekPublicKey>, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
match key {
|
||||
Some(key) => serializer.serialize_str(&key.as_bytes().to_hex()),
|
||||
None => serializer.serialize_none(),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<xDalekPublicKey>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Option::<String>::deserialize(deserializer).and_then(|res| match res {
|
||||
Some(string) => from_hex(&string)
|
||||
.map_err(|err| Error::custom(err.to_string()))
|
||||
.and_then(|bytes: Vec<u8>| {
|
||||
let mut b = [0u8; 32];
|
||||
b.copy_from_slice(&bytes[0..32]);
|
||||
Ok(Some(xDalekPublicKey::from(b)))
|
||||
}),
|
||||
None => Ok(None),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Serializes an ed25519_dalek::Signature to and from hex
|
||||
pub mod dalek_sig_serde {
|
||||
use ed25519_dalek::Signature as DalekSignature;
|
||||
|
|
187
libwallet/src/slatepack/armor.rs
Normal file
187
libwallet/src/slatepack/armor.rs
Normal file
|
@ -0,0 +1,187 @@
|
|||
// Copyright 2020 The Grin Developers
|
||||
//
|
||||
// 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.
|
||||
|
||||
// A note on encoding efficiency: 0.75 for Base64, 0.744 for Base62, 0.732 for Base58
|
||||
// slatepack uses a modified Base58Check encoding to create armored slate payloads:
|
||||
// 1. Take first four bytes of SHA256(SHA256(slate.as_bytes()))
|
||||
// 2. Concatenate result of step 1 and slate.as_bytes()
|
||||
// 3. Base58 encode bytes from step 2
|
||||
// Finally add armor framing and space/newline formatting as desired
|
||||
|
||||
use crate::{Error, ErrorKind};
|
||||
use grin_wallet_util::byte_ser;
|
||||
use regex::Regex;
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::str;
|
||||
|
||||
use super::types::{Slatepack, SlatepackBin};
|
||||
|
||||
// Framing and formatting for slate armor
|
||||
static HEADER: &str = "BEGINSLATEPACK. ";
|
||||
static FOOTER: &str = ". ENDSLATEPACK.";
|
||||
const WORD_LENGTH: usize = 15;
|
||||
|
||||
lazy_static! {
|
||||
static ref HEADER_REGEX: Regex =
|
||||
Regex::new(concat!(r"^[>\n\r\t ]*BEGINSLATEPACK[>\n\r\t ]*$")).unwrap();
|
||||
static ref FOOTER_REGEX: Regex =
|
||||
Regex::new(concat!(r"^[>\n\r\t ]*ENDSLATEPACK[>\n\r\t ]*$")).unwrap();
|
||||
static ref WHITESPACE_LIST: [u8; 5] = [b'>', b'\n', b'\r', b'\t', b' '];
|
||||
}
|
||||
|
||||
/// Wrapper for associated functions
|
||||
pub struct SlatepackArmor;
|
||||
|
||||
impl SlatepackArmor {
|
||||
/// Decode an armored Slatepack
|
||||
pub fn decode(data: &str) -> Result<Vec<u8>, Error> {
|
||||
// Convert the armored slate to bytes for parsing
|
||||
let armor_bytes: Vec<u8> = data.as_bytes().to_vec();
|
||||
// Collect the bytes up to the first period, this is the header
|
||||
let header_bytes = &armor_bytes
|
||||
.iter()
|
||||
.take_while(|byte| **byte != b'.')
|
||||
.cloned()
|
||||
.collect::<Vec<u8>>();
|
||||
// Verify the header...
|
||||
check_header(&header_bytes)?;
|
||||
// Get the length of the header
|
||||
let header_len = *&header_bytes.len() + 1;
|
||||
// Skip the length of the header to read for the payload until the next period
|
||||
let payload_bytes = &armor_bytes[header_len as usize..]
|
||||
.iter()
|
||||
.take_while(|byte| **byte != b'.')
|
||||
.cloned()
|
||||
.collect::<Vec<u8>>();
|
||||
// Get length of the payload to check the footer framing
|
||||
let payload_len = *&payload_bytes.len();
|
||||
// Get footer bytes and verify them
|
||||
let consumed_bytes = header_len + payload_len + 1;
|
||||
let footer_bytes = &armor_bytes[consumed_bytes as usize..]
|
||||
.iter()
|
||||
.take_while(|byte| **byte != b'.')
|
||||
.cloned()
|
||||
.collect::<Vec<u8>>();
|
||||
check_footer(&footer_bytes)?;
|
||||
// Clean up the payload bytes to be deserialized
|
||||
let clean_payload = &payload_bytes
|
||||
.iter()
|
||||
.filter(|byte| !WHITESPACE_LIST.contains(byte))
|
||||
.cloned()
|
||||
.collect::<Vec<u8>>();
|
||||
// Decode payload from base58
|
||||
let base_decode = bs58::decode(&clean_payload).into_vec().unwrap();
|
||||
let error_code = &base_decode[0..4];
|
||||
let slatepack_bytes = &base_decode[4..];
|
||||
// Make sure the error check code is valid for the slate data
|
||||
error_check(&error_code.to_vec(), &slatepack_bytes.to_vec())?;
|
||||
// Return slate as binary or string
|
||||
/*let slatepack_bin = byte_ser::from_bytes::<SlatepackBin>(&slate_bytes).map_err(|e| {
|
||||
error!("Error reading JSON Slatepack: {}", e);
|
||||
ErrorKind::SlatepackDeser
|
||||
})?;*/
|
||||
Ok(slatepack_bytes.to_vec())
|
||||
}
|
||||
|
||||
/// Encode an armored slatepack
|
||||
pub fn encode(slatepack: &Slatepack, num_cols: usize) -> Result<String, Error> {
|
||||
let slatepack_bytes = byte_ser::to_bytes(&SlatepackBin(slatepack.clone()))
|
||||
.map_err(|_| ErrorKind::SlatepackSer)?;
|
||||
let encoded_slatepack = base58check(&slatepack_bytes)?;
|
||||
let formatted_slatepack = format_slatepack(&encoded_slatepack, num_cols)?;
|
||||
Ok(format!("{}{}{}\n", HEADER, formatted_slatepack, FOOTER))
|
||||
}
|
||||
}
|
||||
|
||||
// Takes an error check code and a slate binary and verifies that the code was generated from slate
|
||||
fn error_check(error_code: &Vec<u8>, slate_bytes: &Vec<u8>) -> Result<(), Error> {
|
||||
let new_check = generate_check(&slate_bytes)?;
|
||||
if error_code.iter().eq(new_check.iter()) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ErrorKind::InvalidSlatepackData(
|
||||
"Bad slate error code- some data was corrupted".to_string(),
|
||||
)
|
||||
.into())
|
||||
}
|
||||
}
|
||||
|
||||
// Checks header framing bytes and returns an error if they are invalid
|
||||
fn check_header(header: &Vec<u8>) -> Result<(), Error> {
|
||||
let framing = str::from_utf8(&header).unwrap();
|
||||
if HEADER_REGEX.is_match(framing) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ErrorKind::InvalidSlatepackData("Bad armor header".to_string()).into())
|
||||
}
|
||||
}
|
||||
|
||||
// Checks footer framing bytes and returns an error if they are invalid
|
||||
fn check_footer(footer: &Vec<u8>) -> Result<(), Error> {
|
||||
let framing = str::from_utf8(&footer).unwrap();
|
||||
if FOOTER_REGEX.is_match(framing) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ErrorKind::InvalidSlatepackData("Bad armor footer".to_string()).into())
|
||||
}
|
||||
}
|
||||
|
||||
// MODIFIED Base58Check encoding for slate bytes
|
||||
fn base58check(slate: &[u8]) -> Result<String, Error> {
|
||||
// Serialize the slate json string to a vector of bytes
|
||||
let mut slate_bytes: Vec<u8> = slate.to_vec();
|
||||
// Get the four byte checksum for the slate binary
|
||||
let mut check_bytes: Vec<u8> = generate_check(&slate_bytes)?;
|
||||
// Make a new buffer and concatenate checksum bytes and slate bytes
|
||||
let mut slate_buf = Vec::new();
|
||||
slate_buf.append(&mut check_bytes);
|
||||
slate_buf.append(&mut slate_bytes);
|
||||
// Encode the slate buffer containing the slate binary and checksum bytes as Base58
|
||||
let b58_slate = bs58::encode(slate_buf).into_string();
|
||||
Ok(b58_slate)
|
||||
}
|
||||
|
||||
// Adds human readable formatting to the slate payload for armoring
|
||||
fn format_slatepack(slatepack: &str, num_cols: usize) -> Result<String, Error> {
|
||||
let formatter = slatepack
|
||||
.chars()
|
||||
.enumerate()
|
||||
.flat_map(|(i, c)| {
|
||||
if i != 0 && i % WORD_LENGTH == 0 {
|
||||
if num_cols != 0 && i % (WORD_LENGTH * num_cols) == WORD_LENGTH * 2 {
|
||||
Some('\n')
|
||||
} else {
|
||||
Some(' ')
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
.into_iter()
|
||||
.chain(std::iter::once(c))
|
||||
})
|
||||
.collect::<String>();
|
||||
Ok(formatter)
|
||||
}
|
||||
|
||||
// Returns the first four bytes of a double sha256 hash of some bytes
|
||||
fn generate_check(payload: &Vec<u8>) -> Result<Vec<u8>, Error> {
|
||||
let mut first_hash = Sha256::new();
|
||||
first_hash.input(payload);
|
||||
let mut second_hash = Sha256::new();
|
||||
second_hash.input(first_hash.result());
|
||||
let checksum = second_hash.result();
|
||||
let check_bytes: Vec<u8> = checksum[0..4].to_vec();
|
||||
Ok(check_bytes)
|
||||
}
|
19
libwallet/src/slatepack/mod.rs
Normal file
19
libwallet/src/slatepack/mod.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
// Copyright 2020 The Grin Developers
|
||||
//
|
||||
// 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 armor;
|
||||
mod types;
|
||||
|
||||
pub use self::armor::SlatepackArmor;
|
||||
pub use self::types::{Slatepack, SlatepackBin};
|
491
libwallet/src/slatepack/types.rs
Normal file
491
libwallet/src/slatepack/types.rs
Normal file
|
@ -0,0 +1,491 @@
|
|||
// Copyright 2020 The Grin Developers
|
||||
//
|
||||
// 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.
|
||||
|
||||
/// Slatepack Types + Serialization implementation
|
||||
use x25519_dalek::PublicKey as xDalekPublicKey;
|
||||
use x25519_dalek::StaticSecret;
|
||||
|
||||
use crate::dalek_ser;
|
||||
use crate::grin_core::ser::{self, Readable, Reader, Writeable, Writer};
|
||||
use crate::Error;
|
||||
|
||||
use std::io::{Read, Write};
|
||||
|
||||
pub const SLATEPACK_MAJOR_VERSION: u8 = 1;
|
||||
pub const SLATEPACK_MINOR_VERSION: u8 = 0;
|
||||
|
||||
/// Basic Slatepack definition
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct Slatepack {
|
||||
// Required Fields
|
||||
/// Versioning info
|
||||
#[serde(with = "slatepack_version")]
|
||||
pub slatepack: SlatepackVersion,
|
||||
/// Delivery Mode, 0 = plain_text, 1 = age encrypted
|
||||
pub mode: u8,
|
||||
|
||||
// Optional Fields
|
||||
/// Optional Sender address
|
||||
#[serde(default = "default_sender_none")]
|
||||
#[serde(with = "dalek_ser::option_xdalek_pubkey_serde")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub sender: Option<xDalekPublicKey>,
|
||||
|
||||
// Payload
|
||||
/// Binary payload, can be encrypted or plaintext
|
||||
#[serde(
|
||||
serialize_with = "dalek_ser::as_base64",
|
||||
deserialize_with = "dalek_ser::bytes_from_base64"
|
||||
)]
|
||||
pub payload: Vec<u8>,
|
||||
}
|
||||
|
||||
fn default_sender_none() -> Option<xDalekPublicKey> {
|
||||
None
|
||||
}
|
||||
|
||||
impl Default for Slatepack {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
slatepack: SlatepackVersion {
|
||||
major: SLATEPACK_MAJOR_VERSION,
|
||||
minor: SLATEPACK_MINOR_VERSION,
|
||||
},
|
||||
mode: 0,
|
||||
sender: None,
|
||||
payload: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Slatepack {
|
||||
/// return length of optional fields
|
||||
pub fn opt_fields_len(&self) -> Result<usize, ser::Error> {
|
||||
let mut retval = 0;
|
||||
if self.sender.is_some() {
|
||||
retval += 32;
|
||||
}
|
||||
Ok(retval)
|
||||
}
|
||||
|
||||
/// age encrypt the payload with the given public key
|
||||
pub fn try_encrypt_payload(&mut self, recipients: Vec<xDalekPublicKey>) -> Result<(), Error> {
|
||||
if recipients.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
let rec_keys: Result<Vec<_>, _> = recipients
|
||||
.into_iter()
|
||||
.map(|pk| {
|
||||
let key = age::keys::RecipientKey::X25519(pk);
|
||||
Ok(key)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let keys = match rec_keys {
|
||||
Ok(k) => k,
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
|
||||
let encryptor = age::Encryptor::with_recipients(keys);
|
||||
let mut encrypted = vec![];
|
||||
let mut writer = encryptor.wrap_output(&mut encrypted, age::Format::Binary)?;
|
||||
writer.write_all(&self.payload)?;
|
||||
writer.finish()?;
|
||||
self.payload = encrypted.to_vec();
|
||||
self.mode = 1;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// As above, decrypt if needed
|
||||
pub fn try_decrypt_payload(&mut self, dec_key: Option<&StaticSecret>) -> Result<(), Error> {
|
||||
if self.mode == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
let dec_key = match dec_key {
|
||||
Some(k) => k,
|
||||
None => return Ok(()),
|
||||
};
|
||||
let key = age::keys::SecretKey::X25519(dec_key.clone());
|
||||
let decryptor = match age::Decryptor::new(&self.payload[..])? {
|
||||
age::Decryptor::Recipients(d) => d,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let mut decrypted = vec![];
|
||||
let mut reader = decryptor.decrypt(&[key.into()])?;
|
||||
reader.read_to_end(&mut decrypted)?;
|
||||
self.payload = decrypted.to_vec();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// version check warning
|
||||
// TODO: API?
|
||||
pub fn ver_check_warn(&self) {
|
||||
if self.slatepack.major > SLATEPACK_MAJOR_VERSION
|
||||
|| (self.slatepack.major == SLATEPACK_MAJOR_VERSION
|
||||
&& self.slatepack.minor < SLATEPACK_MINOR_VERSION)
|
||||
{
|
||||
warn!("Incoming Slatepack's version is greater than what this wallet recognizes");
|
||||
warn!("You may need to upgrade if it contains unsupported features");
|
||||
warn!(
|
||||
"Incoming: {}.{}, This wallet: {}.{}",
|
||||
self.slatepack.major,
|
||||
self.slatepack.minor,
|
||||
SLATEPACK_MAJOR_VERSION,
|
||||
SLATEPACK_MINOR_VERSION
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper for outputting slate as binary
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SlatepackBin(pub Slatepack);
|
||||
|
||||
impl serde::Serialize for SlatepackBin {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
let mut vec = vec![];
|
||||
ser::serialize(&mut vec, ser::ProtocolVersion(4), self)
|
||||
.map_err(|err| serde::ser::Error::custom(err.to_string()))?;
|
||||
serializer.serialize_bytes(&vec)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::Deserialize<'de> for SlatepackBin {
|
||||
fn deserialize<D>(deserializer: D) -> Result<SlatepackBin, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
struct SlatepackBinVisitor;
|
||||
|
||||
impl<'de> serde::de::Visitor<'de> for SlatepackBinVisitor {
|
||||
type Value = SlatepackBin;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(formatter, "a serialised binary Slatepack")
|
||||
}
|
||||
|
||||
fn visit_bytes<E>(self, value: &[u8]) -> Result<SlatepackBin, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
let mut reader = std::io::Cursor::new(value.to_vec());
|
||||
let s = ser::deserialize(&mut reader, ser::ProtocolVersion(4))
|
||||
.map_err(|err| serde::de::Error::custom(err.to_string()))?;
|
||||
Ok(s)
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_bytes(SlatepackBinVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl Writeable for SlatepackBin {
|
||||
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
|
||||
let sp = self.0.clone();
|
||||
// Version (2)
|
||||
sp.slatepack.write(writer)?;
|
||||
// Mode (1)
|
||||
writer.write_u8(sp.mode)?;
|
||||
|
||||
// 16 bits of optional content flags (2), most reserved for future use
|
||||
let mut opt_flags: u16 = 0;
|
||||
if sp.sender.is_some() {
|
||||
opt_flags |= 0x01;
|
||||
}
|
||||
writer.write_u16(opt_flags)?;
|
||||
|
||||
// Bytes to skip from here (Start of optional fields) to get to payload
|
||||
writer.write_u32(sp.opt_fields_len()? as u32)?;
|
||||
|
||||
// write optional fields
|
||||
if let Some(s) = sp.sender {
|
||||
writer.write_fixed_bytes(s.as_bytes())?;
|
||||
};
|
||||
|
||||
// Now write payload (length prefixed)
|
||||
writer.write_bytes(sp.payload.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl Readable for SlatepackBin {
|
||||
fn read<R: Reader>(reader: &mut R) -> Result<SlatepackBin, ser::Error> {
|
||||
// Version (2)
|
||||
let slatepack = SlatepackVersion::read(reader)?;
|
||||
// Mode (1)
|
||||
let mode = reader.read_u8()?;
|
||||
if mode > 1 {
|
||||
return Err(ser::Error::UnexpectedData {
|
||||
expected: vec![0, 1],
|
||||
received: vec![mode],
|
||||
});
|
||||
}
|
||||
// optional content flags (2)
|
||||
let opt_flags = reader.read_u16()?;
|
||||
|
||||
// start of header
|
||||
let mut bytes_to_payload = reader.read_u32()?;
|
||||
|
||||
let sender = if opt_flags & 0x01 > 0 {
|
||||
bytes_to_payload -= 32;
|
||||
let bytes = reader.read_fixed_bytes(32)?;
|
||||
let mut b = [0u8; 32];
|
||||
b.copy_from_slice(&bytes[0..32]);
|
||||
Some(xDalekPublicKey::from(b))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// skip over any unknown future fields until header
|
||||
while bytes_to_payload > 0 {
|
||||
let _ = reader.read_u8()?;
|
||||
bytes_to_payload -= 1;
|
||||
}
|
||||
|
||||
let payload = reader.read_bytes_len_prefix()?;
|
||||
|
||||
Ok(SlatepackBin(Slatepack {
|
||||
slatepack,
|
||||
mode,
|
||||
sender,
|
||||
payload,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||
pub struct SlatepackVersion {
|
||||
/// Major
|
||||
pub major: u8,
|
||||
/// Minor
|
||||
pub minor: u8,
|
||||
}
|
||||
|
||||
impl Writeable for SlatepackVersion {
|
||||
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
|
||||
writer.write_u8(self.major)?;
|
||||
writer.write_u8(self.minor)
|
||||
}
|
||||
}
|
||||
|
||||
impl Readable for SlatepackVersion {
|
||||
fn read<R: Reader>(reader: &mut R) -> Result<SlatepackVersion, ser::Error> {
|
||||
let major = reader.read_u8()?;
|
||||
let minor = reader.read_u8()?;
|
||||
Ok(SlatepackVersion { major, minor })
|
||||
}
|
||||
}
|
||||
|
||||
/// Serializes version field JSON
|
||||
pub mod slatepack_version {
|
||||
use serde::de::Error;
|
||||
use serde::{Deserialize, Deserializer, Serializer};
|
||||
|
||||
use super::SlatepackVersion;
|
||||
|
||||
///
|
||||
pub fn serialize<S>(v: &SlatepackVersion, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(&format!("{}.{}", v.major, v.minor))
|
||||
}
|
||||
|
||||
///
|
||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<SlatepackVersion, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
String::deserialize(deserializer).and_then(|s| {
|
||||
let mut retval = SlatepackVersion { major: 0, minor: 0 };
|
||||
let v: Vec<&str> = s.split('.').collect();
|
||||
if v.len() != 2 {
|
||||
return Err(Error::custom("Cannot parse version"));
|
||||
}
|
||||
match u8::from_str_radix(v[0], 10) {
|
||||
Ok(u) => retval.major = u,
|
||||
Err(e) => return Err(Error::custom(format!("Cannot parse version: {}", e))),
|
||||
}
|
||||
match u8::from_str_radix(v[1], 10) {
|
||||
Ok(u) => retval.minor = u,
|
||||
Err(e) => return Err(Error::custom(format!("Cannot parse version: {}", e))),
|
||||
}
|
||||
Ok(retval)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Header struct definition
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct RecipientListEntry {
|
||||
#[serde(with = "dalek_ser::dalek_xpubkey_serde")]
|
||||
/// Public Address
|
||||
pub pub_address: xDalekPublicKey,
|
||||
}
|
||||
|
||||
impl Writeable for RecipientListEntry {
|
||||
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
|
||||
writer.write_fixed_bytes(self.pub_address.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl Readable for RecipientListEntry {
|
||||
fn read<R: Reader>(reader: &mut R) -> Result<RecipientListEntry, ser::Error> {
|
||||
let bytes = reader.read_fixed_bytes(32)?;
|
||||
let mut b = [0u8; 32];
|
||||
b.copy_from_slice(&bytes[0..32]);
|
||||
let pub_address = xDalekPublicKey::from(b);
|
||||
Ok(RecipientListEntry { pub_address })
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn slatepack_bin_basic_ser() -> Result<(), grin_wallet_util::byte_ser::Error> {
|
||||
use grin_wallet_util::byte_ser;
|
||||
let slatepack = SlatepackVersion { major: 1, minor: 0 };
|
||||
let mut payload: Vec<u8> = Vec::with_capacity(243);
|
||||
for _ in 0..payload.capacity() {
|
||||
payload.push(rand::random());
|
||||
}
|
||||
let sp = Slatepack {
|
||||
slatepack,
|
||||
mode: 1,
|
||||
sender: None,
|
||||
payload,
|
||||
};
|
||||
let ser = byte_ser::to_bytes(&SlatepackBin(sp.clone()))?;
|
||||
let deser = byte_ser::from_bytes::<SlatepackBin>(&ser)?.0;
|
||||
assert_eq!(sp.slatepack, deser.slatepack);
|
||||
assert_eq!(sp.mode, deser.mode);
|
||||
assert!(sp.sender.is_none());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn slatepack_bin_opt_fields_ser() -> Result<(), grin_wallet_util::byte_ser::Error> {
|
||||
use grin_wallet_util::byte_ser;
|
||||
use rand::{thread_rng, Rng};
|
||||
let slatepack = SlatepackVersion { major: 1, minor: 0 };
|
||||
let mut payload: Vec<u8> = Vec::with_capacity(243);
|
||||
for _ in 0..payload.capacity() {
|
||||
payload.push(rand::random());
|
||||
}
|
||||
|
||||
// includes optional fields
|
||||
let bytes: [u8; 32] = thread_rng().gen();
|
||||
let sender_secret = StaticSecret::from(bytes);
|
||||
let sender = Some(xDalekPublicKey::from(&sender_secret));
|
||||
let sp = Slatepack {
|
||||
slatepack,
|
||||
mode: 1,
|
||||
sender,
|
||||
payload,
|
||||
};
|
||||
let ser = byte_ser::to_bytes(&SlatepackBin(sp.clone()))?;
|
||||
let deser = byte_ser::from_bytes::<SlatepackBin>(&ser)?.0;
|
||||
assert_eq!(sp.slatepack, deser.slatepack);
|
||||
assert_eq!(sp.mode, deser.mode);
|
||||
assert_eq!(
|
||||
sp.sender.unwrap().as_bytes(),
|
||||
deser.sender.unwrap().as_bytes()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// ensure that a slatepack with unknown data in the optional fields can be read
|
||||
#[test]
|
||||
fn slatepack_bin_future() -> Result<(), grin_wallet_util::byte_ser::Error> {
|
||||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||
use grin_wallet_util::byte_ser;
|
||||
use rand::{thread_rng, Rng};
|
||||
use std::io::Cursor;
|
||||
let slatepack = SlatepackVersion { major: 1, minor: 0 };
|
||||
let payload_size = 1234;
|
||||
let mut payload: Vec<u8> = Vec::with_capacity(payload_size);
|
||||
for _ in 0..payload.capacity() {
|
||||
payload.push(rand::random());
|
||||
}
|
||||
|
||||
let bytes: [u8; 32] = thread_rng().gen();
|
||||
let sender_secret = StaticSecret::from(bytes);
|
||||
let sender = Some(xDalekPublicKey::from(&sender_secret));
|
||||
println!(
|
||||
"sender key len: {}",
|
||||
sender.as_ref().unwrap().as_bytes().len()
|
||||
);
|
||||
|
||||
let sp = Slatepack {
|
||||
slatepack,
|
||||
mode: 1,
|
||||
sender,
|
||||
payload: payload.clone(),
|
||||
};
|
||||
let ser = byte_ser::to_bytes(&SlatepackBin(sp.clone()))?;
|
||||
|
||||
// Add an amount of meaningless (to us) data
|
||||
let num_extra_bytes = 248;
|
||||
let mut new_bytes = vec![];
|
||||
// Version 2
|
||||
// mode 1
|
||||
// opt flags 2
|
||||
// opt fields len (bytes to payload) 4
|
||||
// bytes 5-8 are opt fields len
|
||||
|
||||
// sender 32
|
||||
|
||||
let mut opt_fields_len_bytes = [0u8; 4];
|
||||
opt_fields_len_bytes.copy_from_slice(&ser[5..9]);
|
||||
let mut rdr = Cursor::new(opt_fields_len_bytes.to_vec());
|
||||
let opt_fields_len = rdr.read_u32::<BigEndian>().unwrap();
|
||||
// check this matches what we expect below
|
||||
assert_eq!(opt_fields_len, 32);
|
||||
|
||||
let end_head_pos = opt_fields_len as usize + 8 + 1;
|
||||
|
||||
for i in 0..end_head_pos {
|
||||
new_bytes.push(ser[i]);
|
||||
}
|
||||
for _ in 0..num_extra_bytes {
|
||||
new_bytes.push(thread_rng().gen());
|
||||
}
|
||||
for i in 0..8 {
|
||||
//push payload length prefix
|
||||
new_bytes.push(ser[end_head_pos + i]);
|
||||
}
|
||||
for i in 0..payload_size {
|
||||
new_bytes.push(ser[end_head_pos + 8 + i]);
|
||||
}
|
||||
|
||||
assert_eq!(new_bytes.len(), ser.len() + num_extra_bytes as usize);
|
||||
|
||||
// and set new opt fields length
|
||||
let mut wtr = vec![];
|
||||
wtr.write_u32::<BigEndian>(opt_fields_len + num_extra_bytes as u32)
|
||||
.unwrap();
|
||||
for i in 0..wtr.len() {
|
||||
new_bytes[5 + i] = wtr[i];
|
||||
}
|
||||
|
||||
let deser = byte_ser::from_bytes::<SlatepackBin>(&new_bytes)?.0;
|
||||
assert_eq!(sp.slatepack, deser.slatepack);
|
||||
assert_eq!(sp.mode, deser.mode);
|
||||
assert_eq!(
|
||||
sp.sender.unwrap().as_bytes(),
|
||||
deser.sender.unwrap().as_bytes()
|
||||
);
|
||||
Ok(())
|
||||
}
|
|
@ -12,9 +12,10 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Simple serde byte array serializer, assumes target already
|
||||
// knows how to serialize itself into binary (because that all
|
||||
// this serializer can do)
|
||||
//! Simple serde byte array serializer, assumes target already
|
||||
//! knows how to serialize itself into binary (because that all
|
||||
//! this serializer can do)
|
||||
|
||||
use serde::de::Visitor;
|
||||
use serde::{de, ser, Deserialize, Serialize};
|
||||
use std;
|
|
@ -27,6 +27,9 @@ mod ov3;
|
|||
pub use ov3::OnionV3Address;
|
||||
pub use ov3::OnionV3Error as OnionV3AddressError;
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub mod byte_ser;
|
||||
|
||||
pub use grin_api;
|
||||
pub use grin_chain;
|
||||
pub use grin_core;
|
||||
|
|
Loading…
Reference in a new issue